diff --git a/.github/workflows/academic-citation-tracker.lock.yml b/.github/workflows/academic-citation-tracker.lock.yml index 334003e1a8..47ffd856f3 100644 --- a/.github/workflows/academic-citation-tracker.lock.yml +++ b/.github/workflows/academic-citation-tracker.lock.yml @@ -33,7 +33,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1592,7 +1592,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml index 2e3a02c579..fe7a49ef26 100644 --- a/.github/workflows/agentics-maintenance.yml +++ b/.github/workflows/agentics-maintenance.yml @@ -393,7 +393,7 @@ jobs: - name: Save activity report logs cache if: ${{ always() }} - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./.cache/gh-aw/activity-report-logs key: ${{ steps.activity_report_logs_cache.outputs.cache-primary-key }} @@ -520,7 +520,7 @@ jobs: - name: Save forecast report logs cache if: ${{ always() }} - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ./.github/aw/logs key: ${{ runner.os }}-forecast-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }} diff --git a/.github/workflows/api-coherence-checker.lock.yml b/.github/workflows/api-coherence-checker.lock.yml index 5f402f213c..831331fc67 100644 --- a/.github/workflows/api-coherence-checker.lock.yml +++ b/.github/workflows/api-coherence-checker.lock.yml @@ -33,7 +33,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1590,7 +1590,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/build-z3-cache.yml b/.github/workflows/build-z3-cache.yml index 3898184c7e..74b91750a8 100644 --- a/.github/workflows/build-z3-cache.yml +++ b/.github/workflows/build-z3-cache.yml @@ -45,7 +45,7 @@ jobs: - name: Restore or create cache id: cache-z3 - uses: actions/cache@v6.0.0 + uses: actions/cache@v6.1.0 with: path: | build/z3 diff --git a/.github/workflows/code-conventions-analyzer.lock.yml b/.github/workflows/code-conventions-analyzer.lock.yml index 09a87d5f21..8306bbe917 100644 --- a/.github/workflows/code-conventions-analyzer.lock.yml +++ b/.github/workflows/code-conventions-analyzer.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1647,7 +1647,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/csa-analysis.lock.yml b/.github/workflows/csa-analysis.lock.yml index 847be785ba..59150cf2f7 100644 --- a/.github/workflows/csa-analysis.lock.yml +++ b/.github/workflows/csa-analysis.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1593,7 +1593,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/issue-backlog-processor.lock.yml b/.github/workflows/issue-backlog-processor.lock.yml index d5dace3bf9..8da8a7f1a1 100644 --- a/.github/workflows/issue-backlog-processor.lock.yml +++ b/.github/workflows/issue-backlog-processor.lock.yml @@ -33,7 +33,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1615,7 +1615,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/memory-safety-report.lock.yml b/.github/workflows/memory-safety-report.lock.yml index 06242414b3..a2460b8095 100644 --- a/.github/workflows/memory-safety-report.lock.yml +++ b/.github/workflows/memory-safety-report.lock.yml @@ -35,7 +35,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1667,7 +1667,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index d2febd8e83..df36d1f73d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -33,6 +33,8 @@ jobs: name: "Mac Build x64" runs-on: macos-latest timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -43,7 +45,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be x86_64) run: | @@ -69,6 +71,8 @@ jobs: name: "Mac ARM64 Build" runs-on: macos-latest timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -79,7 +83,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be arm64) run: | diff --git a/.github/workflows/ocaml.yaml b/.github/workflows/ocaml.yaml index 10eaa043fb..ce575ba646 100644 --- a/.github/workflows/ocaml.yaml +++ b/.github/workflows/ocaml.yaml @@ -21,7 +21,7 @@ jobs: # Cache ccache (shared across runs) - name: Cache ccache - uses: actions/cache@v6.0.0 + uses: actions/cache@v6.1.0 with: path: ~/.ccache key: ${{ runner.os }}-ccache-${{ github.sha }} @@ -30,7 +30,7 @@ jobs: # Cache opam (compiler + packages) - name: Cache opam - uses: actions/cache@v6.0.0 + uses: actions/cache@v6.1.0 with: path: ~/.opam key: ${{ runner.os }}-opam-${{ matrix.ocaml-version }}-${{ github.sha }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07387885bc..1e280e056c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,8 @@ jobs: name: "Mac Build x64" runs-on: macos-15 timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -44,7 +46,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be x86_64) run: | @@ -76,6 +78,8 @@ jobs: name: "Mac ARM64 Build" runs-on: macos-15 timeout-minutes: 90 + env: + MACOSX_DEPLOYMENT_TARGET: "13.0" steps: - name: Checkout code uses: actions/checkout@v7.0.0 @@ -86,7 +90,7 @@ jobs: python-version: '3.x' - name: Build - run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 + run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64 --os=osx-13.0 - name: Validate libz3.dylib and z3 architecture (must be arm64) run: | diff --git a/.github/workflows/smtlib-benchmark-finder.lock.yml b/.github/workflows/smtlib-benchmark-finder.lock.yml index 6ce0fd5357..0250d434a5 100644 --- a/.github/workflows/smtlib-benchmark-finder.lock.yml +++ b/.github/workflows/smtlib-benchmark-finder.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -1594,7 +1594,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/specbot-crash-analyzer.lock.yml b/.github/workflows/specbot-crash-analyzer.lock.yml index db5ec29ba1..219036aeab 100644 --- a/.github/workflows/specbot-crash-analyzer.lock.yml +++ b/.github/workflows/specbot-crash-analyzer.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1631,7 +1631,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/tactic-to-simplifier.lock.yml b/.github/workflows/tactic-to-simplifier.lock.yml index 9a6eb38dc2..418d2ebd6f 100644 --- a/.github/workflows/tactic-to-simplifier.lock.yml +++ b/.github/workflows/tactic-to-simplifier.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1599,7 +1599,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/workflow-suggestion-agent.lock.yml b/.github/workflows/workflow-suggestion-agent.lock.yml index a7d48b014d..49cd7630ef 100644 --- a/.github/workflows/workflow-suggestion-agent.lock.yml +++ b/.github/workflows/workflow-suggestion-agent.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1592,7 +1592,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/.github/workflows/zipt-code-reviewer.lock.yml b/.github/workflows/zipt-code-reviewer.lock.yml index 81a7e7e5ed..6bb4ec1f01 100644 --- a/.github/workflows/zipt-code-reviewer.lock.yml +++ b/.github/workflows/zipt-code-reviewer.lock.yml @@ -32,7 +32,7 @@ # # Custom actions used: # - actions/cache/restore@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0 -# - actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 +# - actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -1620,7 +1620,7 @@ jobs: fi - name: Save cache-memory to cache (default) if: steps.check_cache_default.outputs.has_content == 'true' - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: key: memory-none-nopolicy-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }} path: /tmp/gh-aw/cache-memory diff --git a/cmake/compiler_warnings.cmake b/cmake/compiler_warnings.cmake index 2708725875..9e11d9082b 100644 --- a/cmake/compiler_warnings.cmake +++ b/cmake/compiler_warnings.cmake @@ -24,8 +24,9 @@ set(CLANG_ONLY_WARNINGS "-Wsuggest-override" "-Winconsistent-missing-override" "-Wno-missing-field-initializers" - "-Wcast-qual" + "-Wcast-qual" ) + set(MSVC_WARNINGS "/W3") ################################################################################ diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index c35d3aa5b6..34a16789ca 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -447,4 +447,4 @@ extern "C" { return _am.get_i(av); Z3_CATCH_RETURN(0); } -}; +} diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index 17810a4947..806f720b32 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -235,4 +235,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index e01248b31a..6b454530ea 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -358,4 +358,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index d7ea3d3c80..f33f93e29f 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1547,4 +1547,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 1ebb51fcce..dead361cf7 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -161,4 +161,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index 46a8894387..b74fecef3b 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -135,4 +135,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_ast_vector.h b/src/api/api_ast_vector.h index dc1fcb8e6a..f661b8d8d2 100644 --- a/src/api/api_ast_vector.h +++ b/src/api/api_ast_vector.h @@ -21,7 +21,7 @@ Revision History: namespace api { class context; -}; +} struct Z3_ast_vector_ref : public api::object { ast_ref_vector m_ast_vector; diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 5b627944c7..77e7bfbc29 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -399,4 +399,4 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_CATCH_RETURN(0); } -}; +} diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 02bcde2a93..ba926a967f 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -121,4 +121,4 @@ extern "C" { Z3_CATCH; } -}; +} diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 7fe4e40634..624980d507 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -359,7 +359,7 @@ namespace api { return *(m_rcf_manager.get()); } -}; +} // ------------------------ @@ -531,4 +531,4 @@ extern "C" { Z3_CATCH; } -}; +} diff --git a/src/api/api_context.h b/src/api/api_context.h index 7803725886..80fc90569e 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -45,16 +45,16 @@ Revision History: namespace smtlib { class parser; -}; +} namespace realclosure { class manager; -}; +} namespace smt2 { class parser; void free_parser(parser*); -}; +} namespace api { @@ -267,7 +267,7 @@ namespace api { }; -}; +} inline api::context * mk_c(Z3_context c) { return reinterpret_cast(c); } #define RESET_ERROR_CODE() { mk_c(c)->reset_error_code(); } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 61d4aa9fda..072b5c8fff 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -142,7 +142,7 @@ namespace api { void collect_param_descrs(param_descrs & p) { m_context.collect_params(p); } void updt_params(params_ref const& p) { m_context.updt_params(p); } }; -}; +} extern "C" { @@ -705,4 +705,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h index 7f1ceb9bbf..11fbf7e119 100644 --- a/src/api/api_datalog.h +++ b/src/api/api_datalog.h @@ -30,7 +30,7 @@ typedef void (*reduce_assign_callback_fptr)(void*, func_decl*, unsigned, expr*co namespace api { class fixedpoint_context; class context; -}; +} struct Z3_fixedpoint_ref : public api::object { diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index ee381e3e78..8d9d0dd206 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -687,4 +687,4 @@ extern "C" { } -}; +} diff --git a/src/api/api_finite_set.cpp b/src/api/api_finite_set.cpp index 2a2787e2a2..922ffe3f2c 100644 --- a/src/api/api_finite_set.cpp +++ b/src/api/api_finite_set.cpp @@ -184,4 +184,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index aeeb24c419..8ffbd4f13e 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1337,4 +1337,4 @@ extern "C" { Z3_CATCH_RETURN(false); } -}; +} diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 7ef619c9b3..ae7d832a93 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -213,4 +213,4 @@ extern "C" { Z3_CATCH_RETURN(""); } -}; +} diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 3e065fb64e..500cbce37e 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -448,4 +448,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index cee60272ef..d6cc5afbcb 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -489,4 +489,4 @@ extern "C" { } #endif -}; +} diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index bf8fc98714..47f9dba6c0 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -503,4 +503,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index efd33cc057..acc3ab7c7a 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -212,4 +212,4 @@ extern "C" { Z3_CATCH_RETURN(""); } -}; +} diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index a51a7c0696..963fe7fa00 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -106,4 +106,4 @@ extern "C" { } -}; +} diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 55d4a43a8e..ba8345aeeb 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -80,4 +80,4 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 83e2fa5932..de1c6ff48d 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -583,5 +583,5 @@ extern "C" { return Z3_ast_to_string(c, reinterpret_cast(p)); } -}; +} diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index efbeea2e6c..49bc218f3a 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -437,4 +437,4 @@ extern "C" { return from_rcnumeral(rcfm(c).get_sign_condition_coefficient(to_rcnumeral(a), i, j)); Z3_CATCH_RETURN(nullptr); } -}; +} diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 4ceb827397..94756cc584 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -369,4 +369,4 @@ extern "C" { MK_FOURARY(Z3_mk_seq_foldli, mk_c(c)->get_seq_fid(), OP_SEQ_FOLDLI, SKIP); -}; +} diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 3da3619213..2d39e3287a 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -1218,4 +1218,4 @@ extern "C" { -}; +} diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index f29254cba2..0063fe7863 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -61,4 +61,4 @@ extern "C" { } MK_DECL(Z3_mk_transitive_closure, OP_SPECIAL_RELATION_TC); -}; +} diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index a3b8bacf07..b4f97716b7 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -133,4 +133,4 @@ extern "C" { return memory::get_allocation_size(); } -}; +} diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index e0038d8b75..8a639727f5 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -669,4 +669,4 @@ extern "C" { -}; +} diff --git a/src/api/api_util.h b/src/api/api_util.h index ee38c4f275..a1715eaa09 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -46,7 +46,7 @@ namespace api { void inc_ref(); void dec_ref(); }; -}; +} inline ast * to_ast(Z3_ast a) { return reinterpret_cast(a); } inline Z3_ast of_ast(ast* a) { return reinterpret_cast(a); } diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 5172226aee..cfad378a17 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -24,7 +24,7 @@ class sexpr; namespace algebraic_numbers { class anum; class manager; -}; +} enum arith_sort_kind { REAL_SORT, diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 41ed2036bb..f7d65f2b43 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -171,7 +171,7 @@ namespace datatype { size* subst(obj_map& S) override; sort_size eval(obj_map const& S) override { return S[m_param]; } }; - }; + } class def { ast_manager& m; @@ -465,7 +465,7 @@ namespace datatype { sort_ref mk_tuple_datatype(svector> const& elems, symbol const& name, symbol const& test, func_decl_ref& tup, func_decl_ref_vector& accs); }; -}; +} typedef datatype::accessor accessor_decl; typedef datatype::constructor constructor_decl; diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index af4d30add8..1be709324c 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -648,7 +648,7 @@ namespace datalog { m_fid = m.mk_family_id(symbol("datalog_relation")); } return m_fid; - }; + } arith_util& dl_decl_util::arith() const { if (!m_arith) m_arith = alloc(arith_util, m); @@ -788,4 +788,4 @@ namespace datalog { return m.mk_app(f, num_args, args); } -}; +} diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 850d181267..2acbb362a6 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -199,5 +199,5 @@ namespace datalog { }; -}; +} diff --git a/src/ast/euf/euf_ac_plugin.h b/src/ast/euf/euf_ac_plugin.h index 99d01791c7..352337a2f1 100644 --- a/src/ast/euf/euf_ac_plugin.h +++ b/src/ast/euf/euf_ac_plugin.h @@ -319,14 +319,14 @@ namespace euf { struct eq_pp { ac_plugin const& p; eq const& e; - eq_pp(ac_plugin const& p, eq const& e) : p(p), e(e) {}; + eq_pp(ac_plugin const& p, eq const& e) : p(p), e(e) {} eq_pp(ac_plugin const& p, unsigned eq_id): p(p), e(p.m_active[eq_id]) {} std::ostream& display(std::ostream& out) const { return p.display_equation(out, e); } }; struct eq_pp_ll { ac_plugin const& p; eq const& e; - eq_pp_ll(ac_plugin const& p, eq const& e) : p(p), e(e) {}; + eq_pp_ll(ac_plugin const& p, eq const& e) : p(p), e(e) {} eq_pp_ll(ac_plugin const& p, unsigned eq_id) : p(p), e(p.m_active[eq_id]) {} std::ostream& display(std::ostream& out) const { return p.display_equation_ll(out, e); } }; diff --git a/src/ast/euf/euf_etable.cpp b/src/ast/euf/euf_etable.cpp index b308523a54..93be311740 100644 --- a/src/ast/euf/euf_etable.cpp +++ b/src/ast/euf/euf_etable.cpp @@ -276,5 +276,5 @@ namespace euf { return find(n) == n; } -}; +} diff --git a/src/ast/euf/euf_etable.h b/src/ast/euf/euf_etable.h index d6b64e7566..ecac03a228 100644 --- a/src/ast/euf/euf_etable.h +++ b/src/ast/euf/euf_etable.h @@ -179,7 +179,7 @@ namespace euf { }; -}; +} diff --git a/src/ast/euf/euf_mam.h b/src/ast/euf/euf_mam.h index c391f6c09c..a6c20d74b6 100644 --- a/src/ast/euf/euf_mam.h +++ b/src/ast/euf/euf_mam.h @@ -81,5 +81,5 @@ namespace euf { static void ground_subterms(expr* e, ptr_vector& ground); }; -}; +} diff --git a/src/ast/euf/euf_plugin.h b/src/ast/euf/euf_plugin.h index ba6b2d5f93..0a9503ba5d 100644 --- a/src/ast/euf/euf_plugin.h +++ b/src/ast/euf/euf_plugin.h @@ -47,7 +47,7 @@ namespace euf { virtual void merge_eh(enode* n1, enode* n2) = 0; - virtual void diseq_eh(enode* eq) {}; + virtual void diseq_eh(enode* eq) {} virtual void propagate() = 0; diff --git a/src/ast/euf/ho_matcher.cpp b/src/ast/euf/ho_matcher.cpp index a740167ad3..03eb319614 100644 --- a/src/ast/euf/ho_matcher.cpp +++ b/src/ast/euf/ho_matcher.cpp @@ -43,6 +43,7 @@ Author: --*/ #include "ast/euf/ho_matcher.h" +#include "ast/well_sorted.h" @@ -66,7 +67,15 @@ namespace euf { void ho_matcher::search() { IF_VERBOSE(10, display(verbose_stream())); + + unsigned budget = m_max_iterations; while (m.inc()) { + if (budget-- == 0) { + IF_VERBOSE(2, verbose_stream() << "ho_matcher: search budget exhausted\n"); + while (!m_backtrack.empty()) + backtrack(); + break; + } // Q, B -> Q', B'. Push work on the backtrack stack and new work items // e, Bw -> Q', B'. Consume backtrack stack if (!m_goals.empty()) @@ -270,6 +279,11 @@ namespace euf { if (wi.is_done()) return false; + if (wi.level > m_max_depth) { + wi.set_done(); + return false; + } + reduce(wi); auto t = wi.t; @@ -348,6 +362,7 @@ namespace euf { if (qp->get_decl_sort(i) != qt->get_decl_sort(i)) return false; m_goals.push(wi.level, wi.term_offset() + td, qp->get_expr(), qt->get_expr()); + wi.set_done(); return true; } @@ -373,6 +388,9 @@ namespace euf { pats.push_back(to_app(p1)); p1 = to_app(p1)->get_arg(0); } + // innermost select is a meta variable, + // order patterns from inner-most application to outer-most. + pats.reverse(); auto v = to_var(p1); if (wi.is_init()) wi.set_project(); @@ -421,31 +439,53 @@ namespace euf { // H (p1) (p2) = f(t1, .., tn) // H -> \x1 \x2 f(H1(x1, x2), .., Hn(x1, x2)) // H1(p1, p2) = t1, .., Hn(p1, p2) = tn + // + // The select chain `pats` was collected from the outermost + // select down to the flex head, i.e. in reverse order of + // application. The imitating lambda must curry the arguments in + // application order (the first-applied select binds the + // outermost lambda), so process the applications inner-to-outer. + // Without this the constructed lambda has the argument arities + // in the wrong nesting order and its sort disagrees with the + // flex head variable (producing an ill-typed binding). + ptr_vector domain, pat_domain; ptr_vector pat_args; + svector pat_pos; // forward binder position (in domain) of each distinct index expr_ref_vector args(m), pat_vars(m), bound_args(m); vector names; pat_args.push_back(nullptr); pat_vars.push_back(nullptr); + pat_pos.push_back(0); // placeholder for the flex-head slot 0 unsigned num_bound = 0; expr_mark seen; for (auto pat : pats) { for (auto pi : array_select_indices(pat)) { + if (!seen.is_marked(pi)) { + pat_domain.push_back(pi->get_sort()); + pat_args.push_back(pi); + pat_pos.push_back(num_bound); + seen.mark(pi); + } ++num_bound; domain.push_back(pi->get_sort()); names.push_back(symbol(num_bound)); - if (seen.is_marked(pi)) - continue; - pat_domain.push_back(pi->get_sort()); - pat_args.push_back(pi); - seen.mark(pi); } } - for (unsigned i = pat_args.size(); i-- > 1; ) { - auto pi = pat_args.get(i); - pat_vars.push_back(m.mk_var(pat_args.size() - i - 1, pi->get_sort())); - } + // pat_vars[k] references the lambda binder for the k-th distinct + // index and must carry that index' sort, so the reconstructed + // select stays aligned with the flex head's array domain + // (pat_domain). The binder at forward position p has de Bruijn + // index num_bound-1-p (the outermost binder has the highest + // index). Emitting in forward slot order keeps the select + // arguments in the same order as pat_domain even when the + // indices have heterogeneous sorts (otherwise the array plugin + // rejects the ill-ordered select). + for (unsigned k = 1; k < pat_args.size(); ++k) { + unsigned db = num_bound - 1 - pat_pos[k]; + pat_vars.push_back(m.mk_var(db, pat_args.get(k)->get_sort())); + } for (auto ti : *ta) { sort* v_sort = m_array.mk_array_sort(pat_domain.size(), pat_domain.data(), ti->get_sort()); @@ -453,7 +493,8 @@ namespace euf { auto w = m.mk_var(m_subst.size() + wi.pat_offset() + num_bound, v_sort); // shifted by number of bound m_subst.resize(m_subst.size() + 1); pat_args[0] = v; - auto sel = m_array.mk_select(pat_args.size(), pat_args.data()); + expr_ref sel(m); + sel = m_array.mk_select(pat_args.size(), pat_args.data()); m_goals.push(wi.level + 1, wi.term_offset(), sel, ti); pat_vars[0] = w; sel = m_array.mk_select(pat_vars.size(), pat_vars.data()); @@ -469,6 +510,7 @@ namespace euf { num_bound -= sz; lam = m.mk_lambda(sz, domain.data() + num_bound, names.data() + num_bound, lam); } + add_binding(v, wi.pat_offset(), lam); wi.set_done(); return true; @@ -581,6 +623,7 @@ namespace euf { } lam = m.mk_lambda(names.size(), sorts.data(), names.data(), lam); } + SASSERT(is_well_sorted(m, lam)); return lam; } @@ -622,6 +665,8 @@ namespace euf { SASSERT(var_sort); body = m.mk_var(num_binders - i - 1, var_sort); bind_lambdas(num_lambdas, s, body); + SASSERT(body->get_sort() == s); + SASSERT(is_well_sorted(m, body)); return body; } @@ -636,6 +681,8 @@ namespace euf { decl_names.push_back(symbol(i)); } body = m.mk_lambda(sz, decl_sorts.data(), decl_names.data(), body); + SASSERT(s == body->get_sort()); + SASSERT(is_well_sorted(m, body)); } void ho_matcher::add_binding(var* v, unsigned offset, expr* t) { @@ -655,7 +702,6 @@ namespace euf { } auto is_ho = any_of(subterms::all(expr_ref(p, m)), [&](expr* t) { return m_unitary.is_flex(0, t) || - // m.is_lambda_def(t) || is_lambda(t); }); if (!is_ho) @@ -674,8 +720,7 @@ namespace euf { todo.pop_back(); continue; } - if ((m_unitary.is_flex(0, t) && lvl > 1) || // m.is_lambda_def(t) || - is_lambda(t)) { + if ((m_unitary.is_flex(0, t) && lvl > 1) || is_lambda(t)) { if (!contains_pat2abs) m_pat2abs.insert_if_not_there(p, svector>()).push_back({ nb, t }); auto v = m.mk_var(nb++, t->get_sort()); @@ -807,6 +852,7 @@ namespace euf { auto& abs = m_pat2abs[fo_pat]; verbose_stream() << " m_pat2abs size: " << abs.size() << "\n"; for (auto [v, pat] : abs) verbose_stream() << " v=" << v << " pat=" << mk_pp(pat, m) << "\n";); + unsigned base_scope = m_trail.get_num_scopes(); m_trail.push_scope(); m_subst.resize(0); m_subst.resize(s.size()); @@ -824,17 +870,68 @@ namespace euf { TRACE(ho_matching, tout << "refine " << mk_pp(p, m) << "\n" << s << "\n"); unsigned num_bound = 0, level = 0; + for (auto [v, pat] : m_pat2abs[fo_pat]) { + // If a binding's sort disagrees with the pattern variable it would + // fill, substituting it would build an ill-sorted term. This can + // arise for deeply nested multi-select patterns whose de Bruijn + // remapping does not line up, or when E-matching delivers a + // candidate binding whose sort is incompatible with the abstracted + // higher-order pattern. Discard this refinement candidate (produce + // no instance) instead of aborting the whole solve. + if (!subst_sorts_match(m, pat, s, true)) { + m_trail.pop_scope(1); + IF_VERBOSE(0, verbose_stream() << "refine_ho_match: sorts do not match for " << mk_pp(pat, m) << " and " + << s << "\n";); + UNREACHABLE(); + return; + } + } for (auto [v, pat] : m_pat2abs[fo_pat]) { var_subst sub(m, true); auto pat_refined = sub(pat, s); TRACE(ho_matching, tout << mk_pp(pat, m) << " -> " << pat_refined << "\n"); m_goals.push(level, num_bound, pat_refined, m_subst.get(v)); } - search(); + m_trail.pop_scope(1); } + bool ho_matcher::subst_sorts_match(ast_manager& m, expr* t, expr_ref_vector const& s, bool std_order) { + unsigned sz = s.size(); + ptr_buffer es; + svector offs; + es.push_back(t); + offs.push_back(0); + while (!es.empty()) { + expr* e = es.back(); es.pop_back(); + unsigned off = offs.back(); offs.pop_back(); + if (is_var(e)) { + unsigned idx = to_var(e)->get_idx(); + if (idx < off) + continue; + unsigned k = idx - off; + if (k >= sz) + continue; + expr* r = std_order ? s.get(sz - k - 1) : s.get(k); + if (r && r->get_sort() != e->get_sort()) + return false; + } + else if (is_app(e)) { + for (expr* arg : *to_app(e)) { + es.push_back(arg); + offs.push_back(off); + } + } + else if (is_quantifier(e)) { + quantifier* q = to_quantifier(e); + es.push_back(q->get_expr()); + offs.push_back(off + q->get_num_decls()); + } + } + return true; + } + std::ostream& ho_matcher::display(std::ostream& out) const { m_subst.display(out << "subst\n"); m_goals.display(out << "goals\n"); @@ -853,6 +950,7 @@ namespace euf { }; void match_goals::push(unsigned level, unsigned offset, expr_ref const& pat, expr_ref const& t) { + SASSERT(pat->get_sort() == t->get_sort()); match_goal* wi = new (ho.trail().get_region()) match_goal(level, offset, pat, t); ho.trail().push(retire_match_goal(*wi)); // reset on undo wi->init(wi); diff --git a/src/ast/euf/ho_matcher.h b/src/ast/euf/ho_matcher.h index 0235559261..1c952bcbbd 100644 --- a/src/ast/euf/ho_matcher.h +++ b/src/ast/euf/ho_matcher.h @@ -315,6 +315,8 @@ namespace euf { match_goals m_goals; unitary_patterns m_unitary; ptr_vector m_backtrack; + unsigned m_max_depth = 10; // bound on imitation/projection depth (secondary safety cap) + unsigned m_max_iterations = 10000; // per-search expansion-step budget to guarantee termination mutable array_rewriter m_rewriter; array_util m_array; obj_map m_pat2hopat, m_hopat2pat; @@ -386,6 +388,10 @@ namespace euf { void set_on_match(std::function& on_match) { m_on_match = on_match; } + void set_max_depth(unsigned d) { m_max_depth = d; } + + void set_max_iterations(unsigned n) { m_max_iterations = n; } + void operator()(expr *pat, expr *t, unsigned num_vars); void operator()(expr* pat, expr* t, unsigned num_bound, unsigned num_vars); @@ -400,6 +406,13 @@ namespace euf { void refine_ho_match(app* p, expr_ref_vector& s); + // Returns true iff applying the substitution s to t (with the given + // variable ordering) is sort-safe: every free variable of t that is + // bound by s maps to a value of the same sort. Used to defensively + // skip higher-order matches whose bindings would produce ill-typed + // instantiation terms (which would otherwise abort the whole solve). + static bool subst_sorts_match(ast_manager& m, expr* t, expr_ref_vector const& s, bool std_order); + bool is_free(app* p, unsigned i) const { return m_hopat2free_vars[p].contains(i); } quantifier* hoq2q(quantifier* q) const { return m_hoq2q[q]; } diff --git a/src/ast/for_each_expr.cpp b/src/ast/for_each_expr.cpp index ebad5760cb..ee61f7587e 100644 --- a/src/ast/for_each_expr.cpp +++ b/src/ast/for_each_expr.cpp @@ -94,7 +94,7 @@ namespace has_skolem_functions_ns { void operator()(app const * n) const { if (n->get_decl()->is_skolem() && n->get_num_args() > 0) throw found(); } void operator()(quantifier * n) const {} }; -}; +} bool has_skolem_functions(expr * n) { has_skolem_functions_ns::proc p; diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 6583e9893d..a21f21eebf 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -195,4 +195,4 @@ namespace format_ns { return fm(m).mk_app(fid(m), OP_NIL); } -}; +} diff --git a/src/ast/format.h b/src/ast/format.h index 2714d54b74..b7356b8029 100644 --- a/src/ast/format.h +++ b/src/ast/format.h @@ -198,6 +198,6 @@ namespace format_ns { return mk_seq4(m, begin, end, proc, static_cast(strlen(lp)), lp, rp); } -}; +} diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index e237c0dcde..0350694082 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -162,10 +162,10 @@ public: void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; - special_t const & get_min_max_specials() const { return m_min_max_ufs; }; - const2bv_t const & get_const2bv() const { return m_const2bv; }; - const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; }; - uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; }; + special_t const & get_min_max_specials() const { return m_min_max_ufs; } + const2bv_t const & get_const2bv() const { return m_const2bv; } + const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; } + uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; } protected: void mk_one(func_decl *f, expr_ref & sign, expr_ref & result); diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index a9a0c77fcf..a9a4618909 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -167,7 +167,7 @@ namespace macro_manager_ns { } } }; -}; +} /** \brief Mark all func_decls used in exprs as forbidden. diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 094a7cabab..a8fa7187ef 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -71,7 +71,7 @@ void quasi_macros::find_occurrences(expr * e) { default: UNREACHABLE(); } } -}; +} bool quasi_macros::is_non_ground_uninterp(expr const * e) const { return is_non_ground(e) && is_uninterp(e); diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 6fd8c684da..87f17beb87 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -42,9 +42,7 @@ bool smaller_pattern::process(expr * p1, expr * p2) { m_cache.reset(); save(p1, p2); while (!m_todo.empty()) { - expr_pair & curr = m_todo.back(); - p1 = curr.first; - p2 = curr.second; + auto [p1, p2] = m_todo.back(); m_todo.pop_back(); ast_kind k1 = p1->get_kind(); if (k1 != AST_VAR && k1 != p2->get_kind()) @@ -123,12 +121,11 @@ void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) SASSERT(m_info.empty()); SASSERT(m_todo.empty()); SASSERT(m_cache.empty()); + SASSERT(is_well_sorted(m, n)); m_num_bindings = num_bindings; m_todo.push_back(entry(n, 0)); while (!m_todo.empty()) { - entry & e = m_todo.back(); - n = e.m_node; - unsigned delta = e.m_delta; + auto [n, delta] = m_todo.back(); TRACE(collect, tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";); TRACE(collect_info, tout << mk_pp(n, m) << "\n";); if (visit_children(n, delta)) { @@ -177,21 +174,15 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { switch (n->get_kind()) { case AST_VAR: { unsigned idx = to_var(n)->get_idx(); - if (idx >= delta) { - idx = idx - delta; - uint_set free_vars; - if (idx < m_num_bindings) - free_vars.insert(idx); - info * i = nullptr; - if (delta == 0) - i = alloc(info, m, n, free_vars, 1); - else - i = alloc(info, m, m.mk_var(idx, to_var(n)->get_sort()), free_vars, 1); - save(n, delta, i); - } - else { + if (idx >= m_num_bindings + delta) { save(n, delta, nullptr); + return; } + uint_set free_vars; + if (delta <= idx) + free_vars.insert(idx - delta); + info * i = alloc(info, m, n, free_vars, 1); + save(n, delta, i); return; } case AST_APP: { @@ -247,7 +238,8 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { // stating properties about these operators. family_id fid = c->get_family_id(); decl_kind k = c->get_decl_kind(); - if (!free_vars.empty() && + if (!free_vars.empty() && + delta == 0 && (fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) { TRACE(pattern_inference, tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";); m_owner.add_candidate(new_node, free_vars, size); @@ -258,15 +250,13 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { quantifier * q = to_quantifier(n); unsigned num_decls = q->get_num_decls(); info * body_info = nullptr; - m_cache.find(entry(q->get_expr(), delta + num_decls), body_info); - if (body_info == nullptr) { + expr *body = q->get_expr(); + m_cache.find(entry(body, delta + num_decls), body_info); + if (!body_info) { save(n, delta, nullptr); return; } - // The lambda/quantifier itself is a valid sub-term in a pattern. - // Propagate the free variables from the body (they already refer - // to the outer quantifier's bindings) and keep the node as-is. - expr * new_body = body_info->m_node.get(); + expr *new_body = body_info->m_node.get(); quantifier_ref new_q(m); if (new_body != q->get_expr()) new_q = m.update_quantifier(q, new_body); diff --git a/src/ast/polymorphism_inst.cpp b/src/ast/polymorphism_inst.cpp index be91c8f5e3..5070f66d67 100644 --- a/src/ast/polymorphism_inst.cpp +++ b/src/ast/polymorphism_inst.cpp @@ -57,9 +57,11 @@ namespace polymorphism { m_assertions.push_back(e); t.push(push_back_vector(m_assertions)); u.collect_type_vars(e, inst.m_tvs); + auto* init = alloc(substitution, m); inst.m_subst = alloc(substitutions); - inst.m_subst->insert(alloc(substitution, m)); + inst.m_subst->insert(init); m_instances.insert(e, inst); + t.push(new_obj_trail(init)); t.push(new_obj_trail(inst.m_subst)); t.push(insert_map(m_instances, e)); } @@ -107,13 +109,14 @@ namespace polymorphism { auto const& [tv, fns, substs] = m_instances[e]; for (auto* f2 : fns) { - substitution sub1(m), new_sub(m); + substitution sub1(m); if (!u.unify(f1, f2, sub1)) continue; if (substs->contains(&sub1)) continue; substitutions new_substs; for (auto* sub2 : *substs) { + substitution new_sub(m); if (!u.unify(sub1, *sub2, new_sub)) continue; if (substs->contains(&new_sub)) @@ -128,7 +131,7 @@ namespace polymorphism { new_substs.insert(new_sub1); m_from_instantiation.insert(e_inst); m.inc_ref(e_inst); - t.push(insert_ref_map(m, m_from_instantiation, e_inst)); + t.push(insert_ref_map(m, m_from_instantiation, e_inst.get())); } } for (auto* sub2 : new_substs) { diff --git a/src/ast/polymorphism_inst.h b/src/ast/polymorphism_inst.h index 1d171b3143..d9a6ed943d 100644 --- a/src/ast/polymorphism_inst.h +++ b/src/ast/polymorphism_inst.h @@ -58,7 +58,7 @@ namespace polymorphism { void undo() override { i.m_in_decl_queue.mark(i.m_decl_queue.back(), false); i.m_decl_queue.pop_back(); - }; + } }; struct remove_back : public trail { diff --git a/src/ast/polymorphism_util.cpp b/src/ast/polymorphism_util.cpp index 62dd4e9494..a0c2bad502 100644 --- a/src/ast/polymorphism_util.cpp +++ b/src/ast/polymorphism_util.cpp @@ -39,11 +39,13 @@ namespace polymorphism { } unsigned n = s->get_num_parameters(); vector ps; + sort_ref_vector pin(m); // keep substituted sub-sorts alive until mk_sort below for (unsigned i = 0; i < n; ++i) { auto &p = s->get_parameter(i); if (p.is_ast() && is_sort(p.get_ast())) { - sort_ref s = (*this)(to_sort(p.get_ast())); - ps.push_back(parameter(s.get())); + sort_ref ss = (*this)(to_sort(p.get_ast())); + pin.push_back(ss); + ps.push_back(parameter(ss.get())); } else ps.push_back(p); @@ -242,15 +244,27 @@ namespace polymorphism { bool util::unify(substitution const& s1, substitution const& s2, substitution& sub) { sort* v2; - for (auto const& [k, v] : s1) + SASSERT(&s1 != &sub); + SASSERT(&s2 != &sub); + for (auto const& [k, v] : s1) { + // Guard against building a cyclic substitution (e.g. A |-> list(A)), + // which would make substitution application diverge. Such a binding + // means the two substitutions are not simultaneously unifiable. + if (occurs(k, v)) + return false; sub.insert(k, v); + } for (auto const& [k, v] : s2) { if (sub.find(k, v2)) { if (!sub.unify(sub(v), v2)) return false; } - else - sub.insert(k, sub(v)); + else { + sort_ref vr = sub(v); + if (occurs(k, vr)) + return false; + sub.insert(k, vr); + } } return true; } diff --git a/src/ast/quantifier_stat.cpp b/src/ast/quantifier_stat.cpp index 17efb11e9a..a09d8bd928 100644 --- a/src/ast/quantifier_stat.cpp +++ b/src/ast/quantifier_stat.cpp @@ -115,5 +115,5 @@ namespace q { return r; } -}; +} diff --git a/src/ast/quantifier_stat.h b/src/ast/quantifier_stat.h index 45fd58530c..5bff878f1c 100644 --- a/src/ast/quantifier_stat.h +++ b/src/ast/quantifier_stat.h @@ -149,6 +149,6 @@ namespace q { quantifier_stat * operator()(quantifier * q, unsigned generation); }; -}; +} diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index d9fe07dcf3..f876d3ce89 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -60,7 +60,7 @@ namespace recfun { func_decl_ref m_pred; // interval; typedef obj_map bound_map; - bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {}; + bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {} ~bv_bounds(); public: // bounds addition methods br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 6f6a121e48..b2ae76dd78 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2678,8 +2678,15 @@ br_status bv_rewriter::mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result) { } bool bv_rewriter::is_concat_split_target(expr * t) const { + // A bare (de Bruijn) variable is deliberately excluded as a split target: + // splitting (= x (concat ...)) into per-slice extract equalities rewrites + // an eliminable (= VAR t) equality into (= (extract .. VAR) t) fragments + // that destructive equality resolution (der) can no longer use to eliminate + // the bound variable, turning solvable quantified goals into residual + // quantifiers. Splitting is only a bit-blasting heuristic, so skipping it + // here is sound and preserves der-based variable elimination. return - m_split_concat_eq || + (m_split_concat_eq && !is_var(t)) || m_util.is_concat(t) || m_util.is_numeral(t) || m_util.is_bv_or(t); diff --git a/src/ast/rewriter/seq_axioms.h b/src/ast/rewriter/seq_axioms.h index 5838985625..26469ffa2a 100644 --- a/src/ast/rewriter/seq_axioms.h +++ b/src/ast/rewriter/seq_axioms.h @@ -123,5 +123,5 @@ namespace seq { }; -}; +} diff --git a/src/ast/rewriter/seq_eq_solver.cpp b/src/ast/rewriter/seq_eq_solver.cpp index e1ffae7431..a77aaa55ba 100644 --- a/src/ast/rewriter/seq_eq_solver.cpp +++ b/src/ast/rewriter/seq_eq_solver.cpp @@ -727,5 +727,5 @@ namespace seq { -}; +} diff --git a/src/ast/rewriter/seq_eq_solver.h b/src/ast/rewriter/seq_eq_solver.h index c6c5437b79..a3e8a00d47 100644 --- a/src/ast/rewriter/seq_eq_solver.h +++ b/src/ast/rewriter/seq_eq_solver.h @@ -167,5 +167,5 @@ namespace seq { }; -}; +} diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 9e4a6ca72c..79c542f06b 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3263,6 +3263,39 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) { return BR_DONE; } + // (str.in_re e (re.range lo hi)) where a bound is not a concrete character. + // By SMT-LIB semantics (re.range lo hi) is the set of single characters c + // with lo <= c <= hi when lo and hi are themselves single characters, and + // the empty language otherwise; so membership is equivalent to lo, hi and + // e all being single characters with lo <= e <= hi. The derivative engine + // only unfolds ranges whose bounds are concrete characters, so without this + // reduction a range with a symbolic bound is left unsolved (and mk_re_range + // deliberately keeps such a range symbolic rather than unsoundly collapsing + // it to re.empty). Ranges with two concrete single-character bounds keep + // their existing derivative-based handling. + { + expr* rlo = nullptr, *rhi = nullptr; + if (re().is_range(b, rlo, rhi)) { + auto concrete_char = [&](expr* e) { + zstring s; + expr* ch = nullptr; + unsigned uc = 0; + return (str().is_string(e, s) && s.length() == 1) || + (str().is_unit(e, ch) && m_util.is_const_char(ch, uc)); + }; + if (!concrete_char(rlo) || !concrete_char(rhi)) { + expr_ref_vector conj(m()); + conj.push_back(m().mk_eq(str().mk_length(rlo), one())); + conj.push_back(m().mk_eq(str().mk_length(rhi), one())); + conj.push_back(m().mk_eq(str().mk_length(a), one())); + conj.push_back(str().mk_lex_le(rlo, a)); + conj.push_back(str().mk_lex_le(a, rhi)); + result = m().mk_and(conj); + return BR_REWRITE_FULL; + } + } + } + zstring s; if (str().is_string(a, s) && re().is_ground(b)) { // Just check membership and replace by true/false @@ -4122,39 +4155,55 @@ br_status seq_rewriter::mk_re_range(expr* lo, expr* hi, expr_ref& result) { len = min_length(hi).second; if (len > 1) is_empty = true; + // A bound that is provably of length 0 (e.g. the empty string "") can + // likewise never be a single character, so the range is empty. Unlike a + // symbolic bound, max_length == 0 is a provable emptiness fact, so this is + // sound (it is never true for a model-dependent bound such as a variable). if (max_length(lo) == std::make_pair(true, rational(0))) is_empty = true; if (max_length(hi) == std::make_pair(true, rational(0))) is_empty = true; - if (!is_empty) { - if (str().is_string(lo, slo) && slo.length() == 1) - clo = slo[0]; - else if (str().is_unit(lo, lo1) && m_util.is_const_char(lo1, clo)) - ; - else - is_empty = true; - } - if (!is_empty) { - if (str().is_string(hi, shi) && shi.length() == 1) - chi = shi[0]; - else if (str().is_unit(hi, hi1) && m_util.is_const_char(hi1, chi)) - ; - else - is_empty = true; - } - - // clo/chi are only meaningful once both bounds were extracted; an early - // is_empty (from the length checks) leaves them at their default 0, so the - // is_empty return must come before the singleton/ordering checks below. - if (!is_empty && clo > chi) - is_empty = true; + // A provable length constraint (a bound can never be a single character) + // is the only sound way to conclude emptiness for a possibly-symbolic + // bound, so decide emptiness here before attempting to read concrete + // characters. if (is_empty) { sort* srt = re().mk_re(lo->get_sort()); result = re().mk_empty(srt); return BR_DONE; } + // Try to read concrete single-character bounds. A bound that is not a + // syntactic single-character literal is *symbolic* (its value depends on + // the model), NOT empty: collapsing such a range to re.empty is unsound + // (e.g. (re.range x x) is {x} whenever x is a single character), so we + // leave the range unevaluated (BR_FAILED) and let the theory solver + // reason about it. + bool has_clo = false, has_chi = false; + if (str().is_string(lo, slo) && slo.length() == 1) { + clo = slo[0]; + has_clo = true; + } + else if (str().is_unit(lo, lo1) && m_util.is_const_char(lo1, clo)) + has_clo = true; + if (str().is_string(hi, shi) && shi.length() == 1) { + chi = shi[0]; + has_chi = true; + } + else if (str().is_unit(hi, hi1) && m_util.is_const_char(hi1, chi)) + has_chi = true; + + if (!has_clo || !has_chi) + return BR_FAILED; + + // Both bounds are concrete characters: an inverted range is empty. + if (clo > chi) { + sort* srt = re().mk_re(lo->get_sort()); + result = re().mk_empty(srt); + return BR_DONE; + } + // Singleton: re.range "a" "a" → str.to_re "a" if (clo == chi) { result = re().mk_to_re(str().mk_string(zstring(clo))); diff --git a/src/ast/rewriter/seq_skolem.h b/src/ast/rewriter/seq_skolem.h index 4e327f0fa4..39cf2534fe 100644 --- a/src/ast/rewriter/seq_skolem.h +++ b/src/ast/rewriter/seq_skolem.h @@ -171,5 +171,5 @@ namespace seq { }; -}; +} diff --git a/src/ast/rewriter/seq_split.cpp b/src/ast/rewriter/seq_split.cpp index 8977065fc0..fcba3a8d03 100644 --- a/src/ast/rewriter/seq_split.cpp +++ b/src/ast/rewriter/seq_split.cpp @@ -1,3 +1,4 @@ + /*++ Copyright (c) 2026 Microsoft Corporation diff --git a/src/ast/simplifiers/distribute_forall.cpp b/src/ast/simplifiers/distribute_forall.cpp index c7cc6659aa..eb57038103 100644 --- a/src/ast/simplifiers/distribute_forall.cpp +++ b/src/ast/simplifiers/distribute_forall.cpp @@ -101,5 +101,5 @@ void distribute_forall_simplifier::reduce() { if (r != d.fml()) m_fmls.update(idx, dependent_expr(m, r, mp(d.pr(), pr), d.dep())); } -}; +} diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 76a622a456..c7742861b1 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -116,6 +116,7 @@ eliminate: #include "ast/ast_ll_pp.h" #include "ast/ast_pp.h" #include "ast/recfun_decl_plugin.h" +#include "ast/polymorphism_util.h" #include "ast/simplifiers/elim_unconstrained.h" elim_unconstrained::elim_unconstrained(ast_manager& m, dependent_expr_state& fmls) : @@ -425,6 +426,18 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< void elim_unconstrained::reduce() { if (!m_config.m_enabled) return; + // has_type_vars() is a manager-wide flag that is set as soon as any type variable is + // created, including the ones used to define polymorphic signatures of builtin plugins + // (e.g. finite_set) that never occur in the asserted formulas. Only bail out when the + // formulas actually contain type-variable typed terms, which this simplifier cannot invert. + if (m.has_type_vars()) { + polymorphism::util u(m); + for (unsigned i : indices()) { + auto [f, p, d] = m_fmls[i](); + if (u.has_type_vars(f)) + return; + } + } generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); m_inverter.set_model_converter(mc.get()); m_created_compound = true; diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index efaf7f244a..36c132295f 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -62,7 +62,7 @@ void propagate_values::add_sub(dependent_expr const& de) { else if (m.is_value(y) && m_shared.is_shared(x)) m_subst.insert(x, y, dep); } -}; +} void propagate_values::reduce() { m_shared.reset(); diff --git a/src/ast/sls/sls_array_plugin.h b/src/ast/sls/sls_array_plugin.h index 4040e8d57a..84fadc1260 100644 --- a/src/ast/sls/sls_array_plugin.h +++ b/src/ast/sls/sls_array_plugin.h @@ -36,7 +36,7 @@ namespace sls { for (unsigned i = 1; i < a.sel->num_args(); ++i) h ^= a.sel->get_arg(i)->get_root()->hash(); return h; - }; + } }; struct select_args_eq { bool operator()(select_args const& a, select_args const& b) const { @@ -103,13 +103,13 @@ namespace sls { euf::enode* mk_select(euf::egraph& g, euf::enode* b, euf::enode* sel); void resolve_conflict(); - size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); }; + size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); } size_t* to_ptr(euf::enode* t) { return reinterpret_cast((reinterpret_cast(t) << 4) + 1); } size_t* to_ptr(unsigned n) { return reinterpret_cast((size_t)(n << 4) + 3); } bool is_literal(size_t* p) { return (reinterpret_cast(p) & 3) == 0; } bool is_index(size_t* p) { return (reinterpret_cast(p) & 3) == 3; } bool is_enode(size_t* p) { return (reinterpret_cast(p) & 3) == 1; } - sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); }; + sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); } euf::enode* to_enode(size_t* p) { return reinterpret_cast(reinterpret_cast(p) >> 4); } unsigned to_index(size_t* p) { return static_cast(reinterpret_cast(p) >> 4); } diff --git a/src/ast/sls/sls_bv_lookahead.cpp b/src/ast/sls/sls_bv_lookahead.cpp index 87398429e4..b8b46f9d6d 100644 --- a/src/ast/sls/sls_bv_lookahead.cpp +++ b/src/ast/sls/sls_bv_lookahead.cpp @@ -871,8 +871,8 @@ namespace sls { if (m_la.m_config.use_top_level_assertions) return m_la.ctx.input_assertions().get(idx); return m_la.ctx.atom(m_la.ctx.root_literals()[idx].var()); - }; + } -} \ No newline at end of file +} diff --git a/src/ast/sls/sls_bv_tracker.h b/src/ast/sls/sls_bv_tracker.h index a078de5a19..e87190d9b2 100644 --- a/src/ast/sls/sls_bv_tracker.h +++ b/src/ast/sls/sls_bv_tracker.h @@ -40,7 +40,7 @@ class sls_tracker { mpz m_zero, m_one, m_two; struct value_score { - value_score() : value(unsynch_mpz_manager::mk_z(0)) {}; + value_score() : value(unsynch_mpz_manager::mk_z(0)) {} value_score(value_score&&) noexcept = default; value_score(const value_score &other) { m = other.m; diff --git a/src/ast/sls/sls_context.h b/src/ast/sls/sls_context.h index fae5447eb7..8cad22dc16 100644 --- a/src/ast/sls/sls_context.h +++ b/src/ast/sls/sls_context.h @@ -44,15 +44,15 @@ namespace sls { virtual expr_ref get_value(expr* e) = 0; virtual bool is_fixed(expr* e, expr_ref& value) { return false; } virtual void initialize() = 0; - virtual void start_propagation() {}; + virtual void start_propagation() {} virtual bool propagate() = 0; virtual void propagate_literal(sat::literal lit) = 0; virtual void repair_literal(sat::literal lit) = 0; virtual bool repair_down(app* e) = 0; virtual void repair_up(app* e) = 0; virtual bool is_sat() = 0; - virtual void on_rescale() {}; - virtual void on_restart() {}; + virtual void on_rescale() {} + virtual void on_restart() {} virtual std::ostream& display(std::ostream& out) const = 0; virtual bool set_value(expr* e, expr* v) = 0; virtual void collect_statistics(statistics& st) const = 0; diff --git a/src/ast/sls/sls_euf_plugin.h b/src/ast/sls/sls_euf_plugin.h index 45c93a8d06..99523f5077 100644 --- a/src/ast/sls/sls_euf_plugin.h +++ b/src/ast/sls/sls_euf_plugin.h @@ -52,8 +52,8 @@ namespace sls { bool is_user_sort(sort* s) { return s->get_family_id() == user_sort_family_id; } - size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); }; - sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); }; + size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); } + sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); } void validate_model(); void log_clause(sat::literal_vector const& lits); diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index cb8b8b93d2..3fe519369d 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -25,31 +25,73 @@ Revision History: #include "util/warning.h" #include "ast/ast_smt2_pp.h" + namespace { struct well_sorted_proc { - ast_manager & m_manager; - bool m_error; + ast_manager & m; + bool m_error; + ptr_vector m_binding; - well_sorted_proc(ast_manager & m):m_manager(m), m_error(false) {} - - void operator()(var * v) {} + well_sorted_proc(ast_manager & m):m(m), m_error(false) {} - void operator()(quantifier * n) { - expr const * e = n->get_expr(); - if (!is_lambda(n) && !m_manager.is_bool(e)) { - warning_msg("quantifier's body must be a boolean."); - m_error = true; - UNREACHABLE(); + void check(expr* e) { + ptr_vector todo; + expr_mark visited; + todo.push_back(e); + while (!todo.empty()) { + expr* term = todo.back(); + todo.pop_back(); + if (visited.is_marked(term)) + continue; + visited.mark(term, true); + if (is_app(term)) { + for (expr* arg : *to_app(term)) + if (!visited.is_marked(arg)) + todo.push_back(arg); + check_app(to_app(term)); + } + else if (is_var(term)) { + check_var(to_var(term)); + } + else if (is_quantifier(term)) { + check_quantifier(to_quantifier(term)); + } } } - void operator()(app * n) { + void check_quantifier(quantifier * n) { + if (!is_lambda(n) && !m.is_bool(n->get_expr())) { + warning_msg("quantifier's body must be a boolean."); + m_error = true; + } + + unsigned sz = m_binding.size(); + m_binding.append(n->get_num_decls(), n->get_decl_sorts()); + for (unsigned i = 0; i < n->get_num_patterns(); i++) + check(n->get_pattern(i)); + check(n->get_expr()); + m_binding.shrink(sz); + } + + void check_var(var* v) { + if (v->get_idx() >= m_binding.size()) { + return; + } + sort *s = m_binding[m_binding.size() - v->get_idx() - 1]; + if (s != v->get_sort()) { + warning_msg("variable sort does not match binding sort."); + m_error = true; + // UNREACHABLE(); + } + } + + void check_app(app * n) { unsigned num_args = n->get_num_args(); func_decl * decl = n->get_decl(); if (num_args != decl->get_arity() && !decl->is_associative() && !decl->is_right_associative() && !decl->is_left_associative()) { - TRACE(ws, tout << "unexpected number of arguments.\n" << mk_ismt2_pp(n, m_manager);); + TRACE(ws, tout << "unexpected number of arguments.\n" << mk_ismt2_pp(n, m);); warning_msg("unexpected number of arguments."); m_error = true; return; @@ -59,19 +101,20 @@ struct well_sorted_proc { sort * actual_sort = n->get_arg(i)->get_sort(); sort * expected_sort = decl->is_associative() ? decl->get_domain(0) : decl->get_domain(i); if (expected_sort != actual_sort) { - TRACE(tc, tout << "sort mismatch on argument #" << i << ".\n" << mk_ismt2_pp(n, m_manager); - tout << "Sort mismatch for argument " << i+1 << " of " << mk_ismt2_pp(n, m_manager, false) << "\n"; - tout << "Expected sort: " << mk_pp(expected_sort, m_manager) << "\n"; - tout << "Actual sort: " << mk_pp(actual_sort, m_manager) << "\n"; - tout << "Function sort: " << mk_pp(decl, m_manager) << "."; + TRACE(tc, tout << "sort mismatch on argument #" << i << ".\n" << mk_ismt2_pp(n, m); + tout << "Sort mismatch for argument " << i+1 << " of " << mk_ismt2_pp(n, m, false) << "\n"; + tout << "Expected sort: " << mk_pp(expected_sort, m) << "\n"; + tout << "Actual sort: " << mk_pp(actual_sort, m) << "\n"; + tout << "Function sort: " << mk_pp(decl, m) << "."; ); std::ostringstream strm; - strm << "Sort mismatch for argument " << i+1 << " of " << mk_ll_pp(n, m_manager, false) << "\n"; - strm << "Expected sort: " << mk_pp(expected_sort, m_manager) << '\n'; - strm << "Actual sort: " << mk_pp(actual_sort, m_manager) << '\n'; - strm << "Function sort: " << mk_pp(decl, m_manager) << '.'; + strm << "Sort mismatch for argument " << i+1 << " of " << mk_ll_pp(n, m, false) << "\n"; + strm << "Expected sort: " << mk_pp(expected_sort, m) << '\n'; + strm << "Actual sort: " << mk_pp(actual_sort, m) << '\n'; + strm << "Function sort: " << mk_pp(decl, m) << '.'; warning_msg("%s", std::move(strm).str().c_str()); m_error = true; + // UNREACHABLE(); return; } } @@ -82,8 +125,11 @@ struct well_sorted_proc { bool is_well_sorted(ast_manager const & m, expr * n) { well_sorted_proc p(const_cast(m)); - for_each_expr(p, n); + p.check(n); + if (p.m_error) { + IF_VERBOSE(0, verbose_stream() << "expression is not well sorted.\n" << mk_pp(n, const_cast(m)) << "\n";); + IF_VERBOSE(0, verbose_stream() << mk_ll_pp(n, const_cast(m)) << "\n";); + } return !p.m_error; } - diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index d7316619f7..aaf1f1b479 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -581,7 +581,7 @@ class mbp_qel_cmd : public cmd { ptr_vector m_vars; public: - mbp_qel_cmd() : cmd("mbp-qel"){}; + mbp_qel_cmd() : cmd("mbp-qel"){} char const *get_usage() const override { return "(exprs) (vars)"; } char const *get_descr(cmd_context &ctx) const override { return "Model based projection using e-graphs"; @@ -639,7 +639,7 @@ class qel_cmd : public cmd { ptr_vector m_vars; public: - qel_cmd() : cmd("qel"){}; + qel_cmd() : cmd("qel"){} char const *get_usage() const override { return "(lits) (vars)"; } char const *get_descr(cmd_context &ctx) const override { return "QE lite over e-graphs"; @@ -703,7 +703,7 @@ class qe_lite_cmd : public cmd { ptr_vector m_vars; public: - qe_lite_cmd() : cmd("qe-lite"){}; + qe_lite_cmd() : cmd("qe-lite"){} char const *get_usage() const override { return "(lits) (vars)"; } char const *get_descr(cmd_context &ctx) const override { return "QE lite over e-graphs"; diff --git a/src/cmd_context/tptp_frontend.cpp b/src/cmd_context/tptp_frontend.cpp index 4cb5d9451f..e452651571 100644 --- a/src/cmd_context/tptp_frontend.cpp +++ b/src/cmd_context/tptp_frontend.cpp @@ -8,18 +8,23 @@ #include #include -#include "ast/arith_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "ast/expr_abstract.h" -#include "ast/ast_util.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "cmd_context/cmd_context.h" -#include "cmd_context/tptp_frontend.h" -#include "solver/solver.h" #include "util/error_codes.h" #include "util/rational.h" #include "util/timeout.h" #include "util/z3_exception.h" +#include "ast/arith_decl_plugin.h" +#include "ast/array_decl_plugin.h" +#include "ast/decl_collector.h" +#include "ast/expr_abstract.h" +#include "ast/ast_util.h" +#include "ast/polymorphism_util.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "solver/solver.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/tptp_frontend.h" + + bool g_display_statistics = false; bool g_display_model = false; @@ -87,6 +92,7 @@ struct token { std::string text; unsigned line = 1; unsigned col = 1; + bool dquote = false; // true for double-quoted strings ("..."): TPTP distinct objects }; class lexer { @@ -163,6 +169,7 @@ public: if (peek() == '\'' || peek() == '"') { char q = get(); t.kind = token_kind::str; + t.dquote = (q == '"'); while (!eof()) { char c = get(); if (c == '\\' && !eof()) { @@ -291,7 +298,13 @@ class tptp_parser { sort* m_univ; bool m_has_conjecture = false; unsigned m_dropped_formulas = 0; // axioms/definitions skipped due to encoding errors + bool m_has_dependent_type = false; // a "T > $tType" (value-indexed type family) was declared bool m_last_name_quoted = false; + bool m_last_name_dquoted = false; // last parsed name was a double-quoted distinct object + // Distinct objects: TPTP double-quoted strings ("...") denote pairwise distinct + // domain elements. Collected here (deduplicated by name) so a single global + // (distinct ...) constraint can be asserted before solving. + std::unordered_map m_distinct_objects; std::string m_expected_status; // SZS status from the input annotation, if any std::unordered_map m_sorts; sort_ref_vector m_pinned_sorts; // prevents cached sorts from being freed @@ -299,8 +312,78 @@ class tptp_parser { func_decl_ref_vector m_pinned_decls; // prevents cached func_decls from being freed expr_ref_vector m_pinned_exprs; // prevents bound variable apps from being freed std::unordered_map, sort*>> m_typed_decls; + // Polymorphic (TF1/TH1) declarations: a symbol declared with !>[T:$tType] : ... + // keeps genuine type variables (ast_manager::mk_type_var) in its signature rather + // than monomorphizing them onto the universe sort U. m_decl_tvars records, per + // declared symbol name, the ordered list of type-variable sorts introduced by its + // !> binder (used to consume explicit type arguments at THF @-application sites and + // to instantiate the polymorphic declaration). m_poly_decl_arity records the value + // arity (number of non-type arguments) of such a declaration. + std::unordered_map> m_decl_tvars; + std::unordered_map m_poly_decl_arity; + // Parametric type constructors declared as "c : ($tType * .. * $tType) > $tType" + // (e.g. list: $tType > $tType, fun: ($tType*$tType) > $tType). Maps the constructor + // name to its type-argument arity. A use "list(A)" / "fun(A,B)" is built as a genuine + // parametric uninterpreted sort (ast_manager::mk_uninterpreted_sort with sort + // parameters), so distinct instantiations stay distinct and can be matched and + // instantiated by the polymorphism substitution engine, instead of collapsing onto U. + std::unordered_map m_sort_ctors; + // Canonical polymorphic root func_decls for each polymorphic symbol. Every concrete + // (or type-variable) use is created as an instance of the shared root via + // ast_manager::instantiate_polymorphic, so that z3's polymorphism engine links the + // instances (e.g. FINITE@real and the axiom's FINITE@A) to one root and instantiates + // type-variable axioms at the concrete types used elsewhere. m_poly_root_ho holds the + // curried-array (THF @-application) shape; m_poly_root_fo the first-order function shape. + std::unordered_map m_poly_root_ho; + std::unordered_map m_poly_root_fo; + // Type variables introduced by the !> binder while parsing a declaration's type. + // An insertion-ordered list of (name, mk_type_var sort): order matters because + // explicit THF type arguments (f @ T1 @ T2 @ ..) are consumed positionally and + // matched tvars[i] := targs[i]. A std::unordered_map would scramble that order. + std::vector> m_type_vars; std::vector> m_bound; bool m_in_at_arg = false; // true when parsing inside @ argument (lambda body stops consuming @) + unsigned m_tvar_counter = 0; // generates fresh, collision-proof polymorphic type-variable names + unsigned m_rec_depth = 0; + char* m_stack_base = nullptr; // approximate stack anchor captured at the outermost parse frame + // Recursive-descent stack guard. The THF fragment of TPTP admits pathologically + // deep nested applications (some ITP problems contain single formulas nested + // hundreds of levels deep). Each recursive parser frame is large (and frame size + // varies widely by construct), so such formulas can exhaust the process stack. + // A fixed recursion-depth cap is fragile: files with large frames overflow at a + // much smaller depth than files with small frames. Instead we measure the actual + // stack consumed (distance of the current frame from an anchor captured at the + // outermost parse frame) and bail out before the OS stack (/STACK:8MB) is + // exhausted. This adapts automatically to the real per-frame size. On overflow we + // raise a parse_error; the enclosing per-formula handler then drops that formula + // (and counts it, downgrading any later "sat" to GaveUp). + // Budget is well below the 8MB stack, leaving margin for un-guarded helper frames. + static const size_t STACK_BUDGET = 6 * 1024 * 1024; + // Hard depth cap as a backstop against genuine non-terminating recursion (parser + // bugs) independent of stack measurement; far higher than any real TPTP nesting. + static const unsigned RECURSION_LIMIT = 100000; + struct rec_guard { + tptp_parser& p; + rec_guard(tptp_parser& p): p(p) { + char local; + char* cur = &local; + if (!p.m_stack_base) + p.m_stack_base = cur; + else { + size_t used = (p.m_stack_base > cur) + ? static_cast(p.m_stack_base - cur) + : static_cast(cur - p.m_stack_base); + if (used > STACK_BUDGET) + throw parse_error("nesting too deep"); + } + if (++p.m_rec_depth > RECURSION_LIMIT) + throw parse_error("nesting too deep"); + } + ~rec_guard() { + if (--p.m_rec_depth == 0) + p.m_stack_base = nullptr; // re-anchor for the next top-level formula + } + }; struct implicit_var_scope { std::unordered_map vars; ptr_vector order; @@ -426,6 +509,7 @@ class tptp_parser { std::string parse_name() { if (is(token_kind::id) || is(token_kind::str)) { m_last_name_quoted = is(token_kind::str); + m_last_name_dquoted = is(token_kind::str) && m_curr.dquote; std::string r = m_curr.text; next(); return r; @@ -448,20 +532,221 @@ class tptp_parser { return s; } + // Factory for parametric type-constructor sorts: builds (or reuses) the sort + // "name(targs..)" as a genuine uninterpreted sort carrying its type arguments as + // sort parameters. ast_manager::mk_uninterpreted_sort registers the constructor + // name once (assigning it a stable, non-null user-sort family_id / decl_kind) and + // interns instances, so the same name used at different instantiations yields the + // same constructor with distinct parameters — matchable/substitutable by the + // polymorphism engine (polymorphism::substitution recurses through sort parameters). + sort* mk_type_ctor(std::string const& name, ptr_vector const& targs) { + vector ps; + for (sort* a : targs) + ps.push_back(parameter(static_cast(a ? a : m_univ))); + sort* s = m.mk_uninterpreted_sort(symbol(name), ps.size(), ps.data()); + m_pinned_sorts.push_back(s); + return s; + } + // For higher-order types like ($i > $o), create an uninterpreted sort // Function type A > B is represented as Array(A, B). // Multi-argument A * B > C is represented as Array(A, Array(B, C)) (curried). sort* get_ho_sort(ptr_vector const& domain, sort* range) { sort* s = range; - for (int i = (int)domain.size() - 1; i >= 0; --i) - s = m_array.mk_array_sort(domain[i], s); + for (unsigned i = domain.size(); i-- > 0; ) + s = m_array.mk_array_sort(domain[i], s); + m_pinned_sorts.push_back(s); return s; } + // Parse a single explicit type argument following @ at a THF polymorphic + // application site (TH1). Parses exactly one atomic type (a type name or a + // parenthesized mapping type) without consuming the trailing @-application chain, + // which belongs to the value arguments. + sort* parse_type_at_arg() { + if (accept(token_kind::lparen)) { + parsed_type t = parse_type_expr(); + expect(token_kind::rparen, "')'"); + sort* s = t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range); + return s ? s : m_univ; + } + std::string tn = parse_name(); + // Applied type constructor in explicit type-argument position: list(A), fun(A,B). + // Registered parametric constructors only; others monomorphize onto U. + if (accept(token_kind::lparen)) { + ptr_vector targs; + if (!accept(token_kind::rparen)) { + do { + parsed_type t = parse_type_expr(); + targs.push_back(t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range)); + } while (accept(token_kind::comma)); + expect(token_kind::rparen, "')'"); + } + if (m_sort_ctors.find(tn) != m_sort_ctors.end()) + return mk_type_ctor(tn, targs); + return m_univ; + } + return get_sort(tn); + } + + // Parse a single operand within a type-level @-application chain (c @ A @ B). + // Type application is LEFT-associative: c @ A @ B parses as (c @ A) @ B, i.e. + // the constructor c applied to the arguments A and B. Each operand must be + // parsed WITHOUT greedily consuming the trailing @-chain; a nested application + // used as an operand is parenthesized (e.g. list @ ( product_prod @ A @ B )). + // Calling the full parse_type_atom here instead would let the first operand + // swallow the rest of the chain (A @ B), collapsing product_prod @ A @ B into a + // single-argument product_prod(A@B) and desynchronizing the constructor arity. + sort* parse_type_app_operand() { + if (accept(token_kind::lparen)) { + parsed_type t = parse_type_expr(); + expect(token_kind::rparen, "')'"); + sort* s = t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range); + return s ? s : m_univ; + } + std::string n = parse_name(); + if (accept(token_kind::lparen)) { + ptr_vector targs; + if (!accept(token_kind::rparen)) { + do { + parsed_type t = parse_type_expr(); + targs.push_back(t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range)); + } while (accept(token_kind::comma)); + expect(token_kind::rparen, "')'"); + } + if (m_sort_ctors.find(n) != m_sort_ctors.end()) + return mk_type_ctor(n, targs); + return m_univ; + } + return get_sort(n); + } + + // Substitute the polymorphic type variables tvars := targs throughout a template + // signature (domain/range), producing a concrete instance signature. + void instantiate_sig(ptr_vector const& tvars, ptr_vector const& targs, + ptr_vector const& dom_in, sort* rng_in, + ptr_vector& dom_out, sort_ref& rng_out) { + polymorphism::substitution sub(m); + for (unsigned i = 0; i < tvars.size() && i < targs.size(); ++i) + if (tvars[i] != targs[i]) // never insert a self-map: it makes substitution recurse forever + sub.insert(tvars[i], targs[i]); + for (sort* d : dom_in) { + sort_ref s = sub(d); + m_pinned_sorts.push_back(s); + dom_out.push_back(s.get()); + } + rng_out = sub(rng_in); + m_pinned_sorts.push_back(rng_out); + } + static bool is_ttype(sort* s) { return s->get_name() == symbol("$tType"); } + // True if the current token names a type (a builtin type keyword, a declared + // $tType sort, or an in-scope type variable). Used to detect TF1 explicit type + // arguments, which appear as type names in first-order application position. + bool current_is_type_name() const { + if (!is(token_kind::id)) return false; + std::string const& t = m_curr.text; + if (t == "$i" || t == "$o" || t == "$int" || t == "$rat" || t == "$real") + return true; + auto it = m_sorts.find(t); + if (it != m_sorts.end() && it->second != nullptr) + return true; + return m_sort_ctors.find(t) != m_sort_ctors.end(); + } + + // Canonical polymorphic root for the THF curried-array (@-application) shape. + func_decl* poly_root_ho(std::string const& n, ptr_vector const& tdom, sort* trng) { + auto it = m_poly_root_ho.find(n); + if (it != m_poly_root_ho.end()) return it->second; + func_decl* root = m.mk_func_decl(symbol(n), 0, static_cast(nullptr), get_ho_sort(tdom, trng)); + m_pinned_decls.push_back(root); + m_poly_root_ho[n] = root; + return root; + } + + // Canonical polymorphic root for the first-order function shape. + func_decl* poly_root_fo(std::string const& n, ptr_vector const& tdom, sort* trng) { + auto it = m_poly_root_fo.find(n); + if (it != m_poly_root_fo.end()) return it->second; + func_decl* root = m.mk_func_decl(symbol(n), tdom.size(), tdom.data(), trng); + m_pinned_decls.push_back(root); + m_poly_root_fo[n] = root; + return root; + } + + // Instantiate the polymorphic root `root` at a concrete (or type-variable) signature. + // When the root actually carries type variables it is a genuine polymorphic root and + // the instance is registered against it (m_poly_roots) so z3 links the instances; + // otherwise a plain declaration suffices. + func_decl* mk_poly_instance(func_decl* root, unsigned arity, sort* const* dom, sort* rng) { + func_decl* f = root->is_polymorphic() + ? m.instantiate_polymorphic(root, arity, dom, rng) + : m.mk_func_decl(root->get_name(), arity, dom, rng); + m_pinned_decls.push_back(f); + return f; + } + + // Attempt to build an application of a polymorphic (TF1/TH1) declaration `n`. + // Handles three surface forms: + // * TF1 first-order explicit type application f(T.., v..) (fo_targs non-empty) + // * TH1 @-application f @ T.. @ v.. (args empty, @ ahead) + // * first-order type inference from arguments f(v..) with args.size()==value-arity + // On success sets `out` and returns true; otherwise returns false (out untouched). + bool try_poly_application(std::string const& n, expr_ref_vector& args, + ptr_vector const& fo_targs, expr_ref& out) { + auto tvit = m_decl_tvars.find(n); + if (tvit == m_decl_tvars.end()) return false; + ptr_vector const& tvars = tvit->second; + unsigned varity = m_poly_decl_arity[n]; + auto sigit = m_typed_decls.find(mk_typed_key(n, varity)); + if (sigit == m_typed_decls.end()) return false; + ptr_vector const& tdom = sigit->second.first; + sort* trng = sigit->second.second; + + if (!fo_targs.empty()) { + ptr_vector cdom; sort_ref crng(m); + instantiate_sig(tvars, fo_targs, tdom, trng, cdom, crng); + func_decl* f = mk_poly_instance(poly_root_fo(n, tdom, trng), cdom.size(), cdom.data(), crng.get()); + coerce_args(f, args); + out = expr_ref(m.mk_app(f, args.size(), args.data()), m); + return true; + } + + if (args.empty() && is(token_kind::at_tok)) { + ptr_vector targs; + for (unsigned j = 0; j < tvars.size() && is(token_kind::at_tok); ++j) { + next(); // consume @ + targs.push_back(parse_type_at_arg()); + } + ptr_vector cdom; sort_ref crng(m); + instantiate_sig(tvars, targs, tdom, trng, cdom, crng); + sort* ho = get_ho_sort(cdom, crng.get()); + func_decl* f = mk_poly_instance(poly_root_ho(n, tdom, trng), 0, static_cast(nullptr), ho); + out = expr_ref(m.mk_app(f, 0, static_cast(nullptr)), m); + return true; + } + + if (!args.empty() && args.size() == varity) { + polymorphism::substitution sub(m); + bool ok = true; + for (unsigned i = 0; i < varity; ++i) + if (!sub.match(tdom[i], args.get(i)->get_sort())) { ok = false; break; } + if (ok) { + ptr_vector cdom; + for (sort* d : tdom) { sort_ref s = sub(d); m_pinned_sorts.push_back(s); cdom.push_back(s.get()); } + sort_ref crng = sub(trng); m_pinned_sorts.push_back(crng); + func_decl* f = mk_poly_instance(poly_root_fo(n, tdom, trng), varity, cdom.data(), crng.get()); + coerce_args(f, args); + out = expr_ref(m.mk_app(f, args.size(), args.data()), m); + return true; + } + } + return false; + } + static bool is_nonempty_digit_string(std::string const& s) { if (s.empty()) return false; for (char c : s) { @@ -707,6 +992,7 @@ class tptp_parser { // () // ::= $oType | $o | $iType | $i | $tType | $real | $rat | $int parsed_type parse_type_atom() { + rec_guard g(*this); if (accept(token_kind::lparen)) { ptr_vector prod = parse_type_product_raw(); if (accept(token_kind::gt_tok)) { @@ -728,26 +1014,37 @@ class tptp_parser { return parsed_type(prod, nullptr); } std::string n = parse_name(); - // Handle parameterized type constructors: fun(A, B), product_prod(A, B), etc. + // Parameterized type constructor applied with parentheses: fun(A, B), list(A), ... + // Only names registered as genuine parametric type constructors (all type + // arguments) are built as parametric sorts; a value-indexed family such as + // fin: nat > $tType is NOT a type constructor — its "argument" is a value, so it + // is monomorphized onto U (and already flagged as a dependent type at declaration). if (accept(token_kind::lparen)) { - // Consume type arguments — for monomorphization, we ignore them - // and return the base sort (or m_univ if the constructor result is $tType) + ptr_vector targs; if (!accept(token_kind::rparen)) { - do { parse_type_expr(); } while (accept(token_kind::comma)); + do { + parsed_type t = parse_type_expr(); + targs.push_back(t.domain.empty() ? t.range : get_ho_sort(t.domain, t.range)); + } while (accept(token_kind::comma)); expect(token_kind::rparen, "')'"); } - // Return m_univ as the monomorphized result of any type constructor application + if (m_sort_ctors.find(n) != m_sort_ctors.end()) + return parsed_type(mk_type_ctor(n, targs)); + return parsed_type(m_univ); + } + // Type-level application with @: list @ nat, pair @ A @ B, etc. Build the same + // parametric sort constructor from the @-separated type arguments (registered + // constructors only; otherwise monomorphize onto U). + if (is(token_kind::at_tok)) { + ptr_vector targs; + while (accept(token_kind::at_tok)) { + targs.push_back(parse_type_app_operand()); + } + if (m_sort_ctors.find(n) != m_sort_ctors.end()) + return parsed_type(mk_type_ctor(n, targs)); return parsed_type(m_univ); } sort* s = get_sort(n); - // Handle type-level application with @: list @ nat, pair @ A @ B, etc. - // Monomorphize by consuming all @ arguments and returning m_univ. - if (is(token_kind::at_tok)) { - while (accept(token_kind::at_tok)) { - parse_type_atom(); // consume the argument type - } - return parsed_type(m_univ); - } return parsed_type(s); } @@ -755,6 +1052,7 @@ class tptp_parser { // | * // Product types form the domain in mapping types: (A * B) > C ptr_vector parse_type_product_raw() { + rec_guard g(*this); parsed_type first = parse_type_atom(); if (!first.domain.empty() && first.range == nullptr) { // Already a parenthesized product from nested parens @@ -806,6 +1104,7 @@ class tptp_parser { // ::= | // ::= > parsed_type parse_type_product() { + rec_guard g(*this); parsed_type first = parse_type_atom(); // If atom returned a function type and no '*' follows, return it directly if (!first.domain.empty() && first.range != nullptr && !is(token_kind::star_tok)) { @@ -840,30 +1139,40 @@ class tptp_parser { // ::= !> [] : // Parses: atom, atom > atom, (A * B) > C, !>[X:$tType] : T parsed_type parse_type_expr() { + rec_guard g(*this); // Handle type quantification at the expression level for proper domain/range preservation if (is(token_kind::type_forall_tok) || is(token_kind::type_exists_tok)) { next(); expect(token_kind::lbrack, "'['"); - ptr_vector type_params; if (!accept(token_kind::rbrack)) { do { std::string tv = parse_name(); if (accept(token_kind::colon)) parse_type_expr(); // consume $tType annotation - m_sorts.insert_or_assign(tv, m_univ); - type_params.push_back(m_univ); + // Genuine polymorphic type variable (ast_manager::mk_type_var) rather + // than a monomorphizing collapse onto the universe sort U. This keeps + // distinct type parameters distinct and makes the declaration a proper + // polymorphic root, so uses can be instantiated per concrete type. + // + // mk_type_var interns by name, so the name must be globally unique: + // TPTP reuses generic binder names (A, B, ...) across unrelated + // declarations and in formula-level type quantifiers. If a declaration + // binder shared a name with a use-site type variable, they would alias + // to the same sort and instantiate_sig would build a self-substitution + // A := A, which makes polymorphism::substitution recurse forever. A + // '!'-prefixed counter cannot collide with any TPTP identifier. + std::string fresh = "!" + std::to_string(m_tvar_counter++) + "_" + tv; + sort* tvs = m.mk_type_var(symbol(fresh)); + m_pinned_sorts.push_back(tvs); + m_sorts.insert_or_assign(tv, tvs); + m_type_vars.emplace_back(tv, tvs); } while (accept(token_kind::comma)); expect(token_kind::rbrack, "']'"); } expect(token_kind::colon, "':'"); - parsed_type inner = parse_type_expr(); - // Prepend type params to domain - if (!type_params.empty()) { - ptr_vector full_domain = type_params; - full_domain.append(inner.domain); - return parsed_type(full_domain, inner.range); - } - return inner; + // Type variables are type parameters, not value arguments: do NOT prepend + // them to the domain. The inner mapping type references them directly. + return parse_type_expr(); } parsed_type prod = parse_type_product(); if (accept(token_kind::gt_tok)) { @@ -935,6 +1244,7 @@ class tptp_parser { // Grammar: (same as parse_term, primary productions) expr_ref parse_term_primary() { + rec_guard g(*this); if (accept(token_kind::lparen)) { expr_ref e = parse_formula(false); expect(token_kind::rparen, "')'"); @@ -953,10 +1263,11 @@ class tptp_parser { if (n == "$true") return expr_ref(m.mk_true(), m); if (n == "$false") return expr_ref(m.mk_false(), m); - if (is_nonempty_digit_string(n)) { + if (!m_last_name_quoted && is_nonempty_digit_string(n)) { return parse_numeral_from_name(n); } + bool dq_name = m_last_name_dquoted; expr_ref b(m); // Check bound variables: uppercase (quantifier vars) AND lowercase (let-bound names) if (!m_last_name_quoted && find_bound(n, b)) { @@ -979,6 +1290,7 @@ class tptp_parser { return expr_ref(get_or_create_implicit_var(n), m); expr_ref_vector args(m); + ptr_vector fo_targs; // TF1 explicit leading type arguments, if any // $ite needs special parsing: first arg is formula, rest are formulas (branches can be equalities) if (n == "$ite") { expect(token_kind::lparen, "'('"); @@ -994,7 +1306,23 @@ class tptp_parser { } else if (accept(token_kind::lparen)) { if (!accept(token_kind::rparen)) { - do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + // TF1 explicit polymorphic type application: a first-order call to a + // polymorphic symbol supplies its k type arguments first, as type + // names, e.g. mixture(beverage, coffee, S). Parse those k leading + // arguments as sorts rather than terms; the remainder are values. + auto tvit = m_decl_tvars.find(n); + if (tvit != m_decl_tvars.end() && !tvit->second.empty() && current_is_type_name()) { + unsigned ntv = tvit->second.size(); + for (unsigned j = 0; j < ntv; ++j) { + fo_targs.push_back(parse_type_at_arg()); + if (j + 1 < ntv) expect(token_kind::comma, "','"); + } + if (accept(token_kind::comma)) + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } + else { + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } expect(token_kind::rparen, "')'"); } } @@ -1002,12 +1330,24 @@ class tptp_parser { // Table-driven prefix operator dispatch auto op_it = m_ops.find(n); if (op_it != m_ops.end() && !op_it->second.is_infix) { + if (args.empty()) { + while (accept(token_kind::at_tok)) + args.push_back(parse_at_arg()); + } return op_it->second.builder(args); } + // Polymorphic declaration (declared with !>[T:$tType] : ...): instantiate the + // declaration to the concrete type(s) at the use site rather than boxing onto U. + if (expr_ref pe(m); try_poly_application(n, args, fo_targs, pe)) + return pe; + func_decl* f = mk_decl_or_ho_const(n, args.size(), false); coerce_args(f, args); - return expr_ref(args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data()), m); + expr_ref term(args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data()), m); + if (dq_name && args.empty()) + register_distinct_object(n, term); + return term; } // Grammar: ::= | @@ -1019,6 +1359,7 @@ class tptp_parser { // | @ // @ is THF function application, encoded via array select. expr_ref apply_at(expr_ref e) { + rec_guard g(*this); if (!is(token_kind::at_tok)) return e; // @ corresponds to array select (function application) @@ -1029,6 +1370,7 @@ class tptp_parser { sort* arg_sort = arg->get_sort(); sort* result_sort = m.is_bool(arg_sort) ? m.mk_bool_sort() : m_univ; sort* arr_sort = m_array.mk_array_sort(arg_sort, result_sort); + m_pinned_sorts.push_back(arr_sort); e = coerce_arg(e, arr_sort); } else { // Array but domain may not match arg sort — coerce arg @@ -1045,6 +1387,7 @@ class tptp_parser { // parenthesized formula, or lambda. Handles the right-operand of . // Parse an argument to @ — can be a term, a formula (negation, quantifier, parens with connectives), or a lambda expr_ref parse_at_arg() { + rec_guard g(*this); if (accept(token_kind::not_tok)) { expr_ref e = parse_at_arg(); return expr_ref(m.mk_not(ensure_bool(e)), m); @@ -1191,7 +1534,7 @@ class tptp_parser { // For function-style definitions, wrap value in lambdas if (!param_vars.empty()) { expr_ref result = value; - for (int i = (int)param_vars.size() - 1; i >= 0; --i) { + for (unsigned i = param_vars.size(); i-- > 0; ) { expr_ref abs_body(m); expr_abstract(m, 0, 1, (expr* const*)¶m_vars[i], result, abs_body); sort* s = param_vars[i]->get_sort(); @@ -1298,6 +1641,7 @@ class tptp_parser { // ::= = | != // Also handles: let-bound name resolution, implicit variable creation. expr_ref parse_atomic_formula(bool is_boolean) { + rec_guard g(*this); if (accept(token_kind::lparen)) { // Check for parenthesized connective used as higher-order term: (~), (&), (|), etc. if (is(token_kind::not_tok) || is(token_kind::and_tok) || is(token_kind::or_tok) || @@ -1316,24 +1660,37 @@ class tptp_parser { token saved = m_curr; next(); if (accept(token_kind::rparen)) { - // Parenthesized connective: treat as HO constant with array sort + // A parenthesized connective used as a higher-order term, e.g. + // "(~) @ p" or "(|) @ p @ q". Encode it as a genuine lambda over Bool + // carrying the real logical semantics, so that application beta-reduces + // to the actual connective (e.g. "(~) @ p" ==> "not p"). Encoding it as + // an uninterpreted array constant instead would sever it from Boolean + // logic and make valid higher-order theorems spuriously + // CounterSatisfiable (the (~)/(|) applications would be unrelated to the + // truth values of their operands). + (void)op_text; sort* bool_sort = m.mk_bool_sort(); - sort* ho_sort; - if (arity == 1) - ho_sort = m_array.mk_array_sort(bool_sort, bool_sort); - else - ho_sort = m_array.mk_array_sort(bool_sort, m_array.mk_array_sort(bool_sort, bool_sort)); - std::string key = mk_decl_key(op_text, 0, 'h'); - auto it = m_decls.find(key); - func_decl* f; - if (it != m_decls.end()) { - f = it->second; - } else { - f = m.mk_func_decl(symbol(op_text), 0, static_cast(nullptr), ho_sort); - m_pinned_decls.push_back(f); - m_decls.emplace(key, f); + symbol xn("X"), yn("Y"); + if (arity == 1) { + // (~) ==> ^[X:$o] : ~X + expr_ref body(m.mk_not(m.mk_var(0, bool_sort)), m); + return expr_ref(m.mk_lambda(1, &bool_sort, &xn, body), m); } - return expr_ref(m.mk_const(f), m); + // binary connective ==> ^[X:$o] : ^[Y:$o] : (X Y) + // de Bruijn: X is var(1) (outer binder), Y is var(0) (inner binder). + expr* vx = m.mk_var(1, bool_sort); + expr* vy = m.mk_var(0, bool_sort); + expr_ref opbody(m); + switch (saved.kind) { + case token_kind::and_tok: opbody = m.mk_and(vx, vy); break; + case token_kind::or_tok: opbody = m.mk_or(vx, vy); break; + case token_kind::implies_tok: opbody = m.mk_implies(vx, vy); break; + case token_kind::iff_tok: opbody = m.mk_eq(vx, vy); break; + case token_kind::xor_tok: opbody = m.mk_xor(vx, vy); break; + default: opbody = m.mk_eq(vx, vy); break; + } + expr_ref inner(m.mk_lambda(1, &bool_sort, &yn, opbody), m); + return expr_ref(m.mk_lambda(1, &bool_sort, &xn, inner), m); } // Not a parenthesized connective — lparen was consumed and connective was consumed // but ')' didn't follow. Parse as formula with the connective already consumed. @@ -1346,7 +1703,7 @@ class tptp_parser { // resume precedence-climbing parsing from that negated left operand. expr_ref operand = parse_unary_formula(true); expr_ref neg(m.mk_not(ensure_bool(operand)), m); - inner = parse_binary_rest(neg, PREC_IFF, true, true); + inner = parse_binary_rest(neg, PREC_IFF, true); } else { // Binary connective at start of parens — shouldn't happen in valid TPTP throw parse_error("unexpected connective after '(' at " + loc()); @@ -1387,10 +1744,11 @@ class tptp_parser { if (n == "$true") return expr_ref(m.mk_true(), m); if (n == "$false") return expr_ref(m.mk_false(), m); - if (is_nonempty_digit_string(n)) { + if (!m_last_name_quoted && is_nonempty_digit_string(n)) { return parse_numeral_from_name(n); } + bool dq_name = m_last_name_dquoted; // Check if name is let-bound (works for both uppercase vars and lowercase let-bound names) { expr_ref b(m); @@ -1437,11 +1795,62 @@ class tptp_parser { m_bound.push_back(scope); expr_ref body = parse_formula(is_boolean); m_bound.pop_back(); - // Approximate choice as existential quantification - return mk_quantifier(false, vars, body); + // Choice/description operator. @+ is Hilbert's choice (indefinite + // description) and @- is definite description. Both denote an ELEMENT of + // the bound sort T — a witness selected from those satisfying the predicate + // — NOT a Boolean. Encode as Z3's array OP_CHOICE applied to the predicate + // lambda (λX:T. body), which yields a term of sort T (cf. smt2parser). + if (vars.empty()) + return body; + expr_ref pred = ensure_bool(body); + // OP_CHOICE is single-arity. With several binders choose over the first + // variable and existentially bind the remainder inside the predicate. + if (vars.size() > 1) { + ptr_vector rest; + for (unsigned i = 1; i < vars.size(); ++i) rest.push_back(vars[i]); + pred = expr_ref(::mk_exists(m, rest.size(), rest.data(), pred.get()), m); + } + app* xvar = vars[0]; + expr_ref abs_body(m); + expr_abstract(m, 0, 1, (expr* const*)&xvar, pred, abs_body); + sort* xs = xvar->get_sort(); + symbol xnm = xvar->get_decl()->get_name(); + expr_ref lam(m.mk_lambda(1, &xs, &xnm, abs_body), m); + return expr_ref(m_array.mk_choice(lam), m); + } + + // Universal (!!) and existential (??) quantifier combinators (TPTP THF): + // !! : !>[A] : ((A > $o) > $o) !! @ A @ P == ! [X:A] : (P @ X) + // ?? : !>[A] : ((A > $o) > $o) ?? @ A @ P == ? [X:A] : (P @ X) + // These are the quantifier-as-operator forms (the files typically also carry + // a defining axiom of exactly this shape). A TH1 use supplies the domain type + // A explicitly first (!! @ A @ P); a TH0 use omits it and A is recovered from + // the predicate's array sort. The predicate P has sort (A > $o), encoded as + // Array(A, $o); it is applied to the fresh bound variable by array select, + // and the whole term is a Boolean quantifier (no boxing coercion). + if ((n == "!!" || n == "??") && is(token_kind::at_tok)) { + bool is_forall = (n == "!!"); + accept(token_kind::at_tok); + sort* dom = nullptr; + if (current_is_type_name()) { + dom = parse_type_at_arg(); + expect(token_kind::at_tok, "'@'"); + } + expr_ref pred = parse_at_arg(); + sort* ps = pred->get_sort(); + if (!dom) + dom = m_array.is_array(ps) ? get_array_domain(ps, 0) : m_univ; + app* c = m.mk_const(symbol(("!q" + std::to_string(m_tvar_counter++)).c_str()), dom); + m_pinned_exprs.push_back(c); + expr_ref body = ensure_bool(expr_ref(m_array.mk_select(pred.get(), c), m)); + app* cs[1] = { c }; + expr_ref q = is_forall ? ::mk_forall(m, 1, cs, body.get()) + : ::mk_exists(m, 1, cs, body.get()); + return q; } expr_ref_vector args(m); + ptr_vector fo_targs; // TF1 explicit leading type arguments, if any // $ite needs special parsing: first arg is formula, rest are formulas (branches can be equalities) if (n == "$ite") { expect(token_kind::lparen, "'('"); @@ -1457,7 +1866,23 @@ class tptp_parser { } else if (accept(token_kind::lparen)) { if (!accept(token_kind::rparen)) { - do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + // TF1 explicit polymorphic type application: a first-order call to a + // polymorphic symbol supplies its k type arguments first, as type + // names, e.g. mixture(beverage, coffee, S). Parse those k leading + // arguments as sorts rather than terms; the remainder are values. + auto tvit = m_decl_tvars.find(n); + if (tvit != m_decl_tvars.end() && !tvit->second.empty() && current_is_type_name()) { + unsigned ntv = tvit->second.size(); + for (unsigned j = 0; j < ntv; ++j) { + fo_targs.push_back(parse_type_at_arg()); + if (j + 1 < ntv) expect(token_kind::comma, "','"); + } + if (accept(token_kind::comma)) + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } + else { + do { args.push_back(parse_term()); } while (accept(token_kind::comma)); + } expect(token_kind::rparen, "')'"); } } @@ -1465,6 +1890,10 @@ class tptp_parser { // Table-driven prefix operator dispatch auto op_it = m_ops.find(n); if (op_it != m_ops.end() && !op_it->second.is_infix) { + if (args.empty()) { + while (accept(token_kind::at_tok)) + args.push_back(parse_at_arg()); + } return op_it->second.builder(args); } @@ -1480,6 +1909,12 @@ class tptp_parser { if (has_lhs) return lhs; + // Polymorphic declaration (declared with !>[T:$tType] : ...). Instead of the + // monomorphizing box coercions that collapse every type parameter onto U, we + // instantiate the declaration to the concrete type(s) at each use. + if (expr_ref pe(m); try_poly_application(n, args, fo_targs, pe)) + return pe; + auto typed = m_typed_decls.find(mk_typed_key(n, args.size())); if (typed != m_typed_decls.end()) { func_decl* f = args.empty() ? mk_decl_or_ho_const(n, 0, false) : mk_decl(n, args.size(), false); @@ -1492,7 +1927,10 @@ class tptp_parser { func_decl* pred = mk_decl_or_ho_const(n, args.size(), is_boolean); coerce_args(pred, args); - return expr_ref(m.mk_app(pred, args.size(), args.data()), m); + expr_ref atom(m.mk_app(pred, args.size(), args.data()), m); + if (dq_name && args.empty() && !m.is_bool(atom)) + register_distinct_object(n, atom); + return atom; } // Grammar: ::= ^ [] : @@ -1537,7 +1975,7 @@ class tptp_parser { // Create nested single-variable lambdas (curried) to match our curried array encoding. // ^[X:A, Y:B] : body becomes ^[X:A] : (^[Y:B] : body) with sort Array(A, Array(B, body_sort)) expr_ref result = body; - for (int i = (int)vars.size() - 1; i >= 0; --i) { + for (unsigned i = vars.size(); i-- > 0; ) { expr_ref abs_body(m); expr_abstract(m, 0, 1, (expr* const*)&vars[i], result, abs_body); sort* s = vars[i]->get_sort(); @@ -1555,6 +1993,7 @@ class tptp_parser { // ::= ! | ? // Also handles: $ite, $let, lambda (^), parenthesized formulas, and atomic formulas. expr_ref parse_unary_formula(bool is_boolean) { + rec_guard g(*this); if (accept(token_kind::not_tok)) { expr_ref e = parse_unary_formula(true); return expr_ref(m.mk_not(ensure_bool(e)), m); @@ -1639,6 +2078,10 @@ class tptp_parser { ptr_vector vars; std::unordered_map scope; + // $tType binders that we turn into genuine type variables so the body + // becomes a polymorphic axiom. Saved so we can restore the enclosing + // type-variable scope after parsing the body. + std::vector> saved_tvars; if (!accept(token_kind::rbrack)) { do { std::string v = parse_name(); @@ -1652,11 +2095,25 @@ class tptp_parser { s = t.range; } } - // Monomorphize: $tType-sorted variables become U-sorted - // and register them as sorts for subsequent type references + // A $tType-sorted binder is genuine type quantification (THF/TH1 + // "! [A: $tType] : ..." quantifies over types just like "!>"). + // For universal quantifiers keep the type variable (mk_type_var) + // so uses of v in the body are parametric and theory_polymorphism + // instantiates them on demand. Existential type quantification has + // no first-class encoding, so fall back to the universe sort U. + // Register v BEFORE parsing later binders so a subsequent value + // binder "X:A" resolves A to this type variable. if (is_ttype(s)) { - s = m_univ; - m_sorts.insert_or_assign(v, m_univ); + auto it = m_sorts.find(v); + saved_tvars.emplace_back(v, it == m_sorts.end() ? nullptr : it->second); + if (is_forall) { + sort* tvs = m.mk_type_var(symbol(v)); + m_pinned_sorts.push_back(tvs); + m_sorts.insert_or_assign(v, tvs); + } + else + m_sorts.insert_or_assign(v, m_univ); + continue; // not a value-level bound variable } app* c = m.mk_const(symbol(v), s); m_pinned_exprs.push_back(c); @@ -1676,25 +2133,54 @@ class tptp_parser { // and "! [X] : (...) => g" keeps "=> g" outside the quantifier scope. expr_ref body = parse_expr(PREC_EQ, true, is_boolean); m_bound.pop_back(); + // Restore the enclosing type-variable scope. + for (auto const& pr : saved_tvars) { + if (pr.second) m_sorts.insert_or_assign(pr.first, pr.second); + else m_sorts.erase(pr.first); + } + // Pure type quantification (no value binders): the body is already a + // polymorphic axiom, so return it directly. + if (vars.empty()) + return body; return mk_quantifier(is_forall, vars, body); } // Type quantification in formula context: !>[A: $tType, ...] : body - // Erase type variables and parse body as formula if (is(token_kind::type_forall_tok) || is(token_kind::type_exists_tok)) { + bool is_forall = is(token_kind::type_forall_tok); next(); expect(token_kind::lbrack, "'['"); + std::vector> saved; if (!accept(token_kind::rbrack)) { do { std::string tv = parse_name(); if (accept(token_kind::colon)) parse_type_expr(); // consume $tType annotation - m_sorts.insert_or_assign(tv, m_univ); + auto it = m_sorts.find(tv); + saved.emplace_back(tv, it == m_sorts.end() ? nullptr : it->second); + // Universal type quantification is genuine parametric polymorphism: + // keep the type variable (mk_type_var) so the body becomes a + // polymorphic axiom that theory_polymorphism instantiates on demand. + // Existential type quantification has no first-class encoding here, so + // fall back to the universe sort U for it. + if (is_forall) { + sort* tvs = m.mk_type_var(symbol(tv)); + m_pinned_sorts.push_back(tvs); + m_sorts.insert_or_assign(tv, tvs); + } + else + m_sorts.insert_or_assign(tv, m_univ); } while (accept(token_kind::comma)); expect(token_kind::rbrack, "']'"); } expect(token_kind::colon, "':'"); - return parse_formula(is_boolean); + expr_ref body = parse_formula(is_boolean); + // Restore the enclosing type-variable scope. + for (auto const& pr : saved) { + if (pr.second) m_sorts.insert_or_assign(pr.first, pr.second); + else m_sorts.erase(pr.first); + } + return body; } return parse_atomic_formula(is_boolean); @@ -1710,14 +2196,16 @@ class tptp_parser { // | & // Implements a Pratt-style (precedence climbing) parser for binary connectives. expr_ref parse_expr(unsigned min_prec, bool consume_at, bool is_boolean) { + rec_guard g(*this); expr_ref e = parse_unary_formula(is_boolean); - return parse_binary_rest(e, min_prec, consume_at, m.is_bool(e)); + return parse_binary_rest(e, min_prec, consume_at); } // Precedence-climbing loop continued from an already-parsed left operand `e`. // Split out from parse_expr so callers that have consumed a leading unary unit // (e.g. a '~' immediately after '(') can resume binary-connective parsing. - expr_ref parse_binary_rest(expr_ref e, unsigned min_prec, bool consume_at = true, bool is_boolean = true) { + expr_ref parse_binary_rest(expr_ref e, unsigned min_prec, bool consume_at = true) { + rec_guard g(*this); for (;;) { // Handle @ (function application) with highest precedence // But NOT when we're inside a lambda body that's an @ argument @@ -1731,6 +2219,7 @@ class tptp_parser { // If arg is Bool-sorted, result is likely Bool too (modal/connective application) sort* result_sort = m.is_bool(arg_sort) ? m.mk_bool_sort() : m_univ; sort* arr_sort = m_array.mk_array_sort(arg_sort, result_sort); + m_pinned_sorts.push_back(arr_sort); e = coerce_arg(e, arr_sort); } else { // Array but domain may not match arg sort — coerce arg @@ -1748,7 +2237,15 @@ class tptp_parser { if (it->second.precedence < min_prec) break; next(); // consume the operator token unsigned next_prec = it->second.right_assoc ? it->second.precedence : it->second.precedence + 1; - expr_ref rhs = parse_expr(next_prec, consume_at, is_boolean); + // Operands of every connective except '='/'!=' are Boolean; only equality + // takes term operands. Derive the operand context from the operator rather + // than inheriting is_boolean from the left operand. Otherwise, once a + // term-valued equality literal (e.g. 'a = b') sets is_boolean to false, a + // predicate atom later in the same clause ('a = b | q') would be parsed as a + // term and boxed into '$box_U_to_Bool(q)', severing it from the Boolean + // predicate 'q' used elsewhere and making refutable problems satisfiable. + bool rhs_is_boolean = it->second.precedence != PREC_EQ; + expr_ref rhs = parse_expr(next_prec, consume_at, rhs_is_boolean); expr_ref_vector args(m); args.push_back(e); args.push_back(rhs); @@ -1766,23 +2263,77 @@ class tptp_parser { while (accept(token_kind::lparen)) ++lparen_count; std::string name = parse_name(); expect(token_kind::colon, "':'"); + m_type_vars.clear(); parsed_type t = parse_type_expr(); while (lparen_count-- > 0) expect(token_kind::rparen, "')'"); + // Capture and tear down the type-variable scope introduced by a !> binder. + // The type_var sorts live on in the stored signature; only the name->sort + // bindings are removed so a later declaration reusing the same variable name + // (e.g. Tv0) does not see this declaration's variables. + ptr_vector tvars; + for (auto const& kv : m_type_vars) { + tvars.push_back(kv.second); + m_sorts.erase(kv.first); + } + m_type_vars.clear(); + if (t.domain.empty() && is_ttype(t.range)) { - // Sort declaration: monomorphize to m_univ - m_sorts.insert_or_assign(name, m_univ); + // Sort declaration: give every declared type its own distinct uninterpreted + // sort. Collapsing all declared $tType sorts onto a single m_univ is unsound: + // a per-type constraint such as "![H:human]:H=jon" would then also constrain + // unrelated sorts (e.g. cats), turning satisfiable axiom sets into a spurious + // contradiction and reporting Theorem where the conjecture is CounterSatisfiable. + if (m_sorts.find(name) == m_sorts.end()) { + sort* s = m.mk_uninterpreted_sort(symbol(name)); + m_pinned_sorts.push_back(s); + m_sorts.emplace(name, s); + } + // A prior *use* of the name (before its declaration) already created a fresh + // sort via parse_defined_sort; keep that same sort so uses and the declaration + // agree. return; } - // Monomorphize: replace $tType in domain/range with m_univ + // A declaration whose result is $tType is a type constructor. If every argument + // is itself a type ($tType), it is a parametric type constructor (e.g. + // list: $tType > $tType, fun: ($tType*$tType) > $tType): register it so uses + // "list(A)" build genuine parametric sorts. Only a constructor with a *value* + // argument (e.g. fin: nat > $tType) is a dependent type family, which Z3 cannot + // encode faithfully; flag those so verdicts are downgraded to GaveUp. + if (t.range && is_ttype(t.range)) { + bool all_type_args = true; + for (sort* s : t.domain) + if (!is_ttype(s)) { all_type_args = false; break; } + if (all_type_args) { + m_sort_ctors[name] = t.domain.size(); + return; + } + } + + // Monomorphize: replace any stray $tType in domain/range with m_univ (genuine + // type variables are already mk_type_var sorts and are left intact). for (auto& s : t.domain) { if (is_ttype(s)) s = m_univ; } - if (t.range && is_ttype(t.range)) t.range = m_univ; + if (t.range && is_ttype(t.range)) { + // A declaration "f: T.. > $tType" with a value argument is a value-indexed + // type family (a dependent type constructor, e.g. "fin: nat > $tType"). Z3's + // parametric polymorphism cannot faithfully encode dependent types: we + // approximate "fin @ N" by a universe element, which is unsound (it can prove + // a conjecture that is only CounterSatisfiable). Flag the problem so any + // sat/unsat verdict is downgraded to GaveUp rather than reported as a + // (possibly spurious) Theorem/CounterSatisfiable. + m_has_dependent_type = true; + t.range = m_univ; + } m_typed_decls.insert_or_assign(mk_typed_key(name, t.domain.size()), std::make_pair(t.domain, t.range)); + if (!tvars.empty()) { + m_decl_tvars[name] = tvars; + m_poly_decl_arity[name] = t.domain.size(); + } } static bool file_exists(std::string const& f) { @@ -1815,14 +2366,15 @@ class tptp_parser { // Try relative to current file's directory std::string local = normalize_path(dirname(curr_file) + "/" + name); if (file_exists(local)) return local; - #if 0 - // Try TPTP environment variable (standard TPTP convention) + // Try TPTP environment variable (standard TPTP convention): includes such as + // "Axioms/MAT001^0.ax" are resolved relative to the TPTP root directory named + // by $TPTP. This is required when a problem is run from a directory that does + // not contain the Axioms/ tree (e.g. an isolated benchmark harness workspace). char const* root = std::getenv("TPTP"); if (root) { std::string env = normalize_path(std::string(root) + "/" + name); if (file_exists(env)) return env; } - #endif // Walk up ancestor directories of the current file. TPTP include paths are // relative to the TPTP root directory (e.g. "Axioms/BOO001-0.ax"), while the // problem file typically lives in a subdirectory such as "Problems/BOO/". @@ -1874,7 +2426,23 @@ class tptp_parser { expect(token_kind::comma, "','"); if (role == "type") { - parse_type_decl_formula(); + try { + parse_type_decl_formula(); + } catch (std::exception const& ex) { + // A type declaration that is too deeply nested to parse within the + // stack budget (recursion guard) or otherwise malformed: drop it and + // resync. Dropping a type declaration is counted so a later "sat" + // verdict is downgraded to GaveUp rather than reported as a certified + // model (uses of the undeclared symbol would themselves be dropped). + ++m_dropped_formulas; + std::ostringstream oss; + oss << "skipping type declaration '" << formula_name << "' due to: " << ex.what(); + warning_msg(oss.str().c_str()); + while (!is(token_kind::eof_tok) && !is(token_kind::dot)) + next(); + if (is(token_kind::dot)) next(); + return; + } } else if (role == "logic") { // Modal logic declarations ($modal == [...]) — skip the formula body @@ -1897,6 +2465,7 @@ class tptp_parser { m_has_conjecture = true; f = m.mk_not(f); } + SASSERT(is_well_sorted(m, f)); m_cmd.assert_expr(f); } catch (z3_exception const& ex) { // Sort mismatch or other semantic error in this formula — skip it. @@ -2176,6 +2745,12 @@ public: }}; } + // Record a double-quoted string constant as a TPTP distinct object (deduplicated by name). + void register_distinct_object(std::string const& name, expr* c) { + if (m_distinct_objects.emplace(name, c).second) + m_pinned_exprs.push_back(c); + } + void parse_input(std::istream& in, std::string const& current_file) { // Save parser state so that included files don't clobber the caller's lexer. std::string saved_input = std::move(m_input); @@ -2213,12 +2788,27 @@ public: bool has_conjecture() const { return m_has_conjecture; } + // TPTP double-quoted strings ("...") denote pairwise distinct domain elements. + // Assert a single global distinctness constraint over all collected distinct objects + // so that e.g. "Apple" != "Microsoft" is recognized as a theorem. + void assert_distinct_objects() { + if (m_distinct_objects.size() < 2) return; + expr_ref_vector objs(m); + for (auto const& kv : m_distinct_objects) + objs.push_back(kv.second); + m_cmd.assert_expr(expr_ref(m.mk_distinct(objs.size(), objs.data()), m)); + } + // Number of axioms/definitions that were dropped during parsing because the // higher-order encoding could not type-check them. When non-zero, a "sat" // verdict cannot be trusted (the missing constraints may be exactly what // makes the problem unsatisfiable). unsigned dropped_formulas() const { return m_dropped_formulas; } + // True if the problem declares a value-indexed type family ("T > $tType"), a + // dependent type that our polymorphic encoding cannot represent soundly. + bool has_dependent_type() const { return m_has_dependent_type; } + std::string const& expected_status() const { return m_expected_status; } // Scan TPTP comments for an SZS/Status annotation, e.g. @@ -2276,6 +2866,7 @@ public: }; expr_ref tptp_parser::parse_term() { + rec_guard g(*this); expr_ref e = parse_term_primary(); if (!is(token_kind::at_tok)) return e; // @ corresponds to array select (function application) @@ -2285,6 +2876,7 @@ expr_ref tptp_parser::parse_term() { if (!m_array.is_array(e_sort)) { sort* arg_sort = arg->get_sort(); sort* arr_sort = m_array.mk_array_sort(arg_sort, m_univ); + m_pinned_sorts.push_back(arr_sort); e = coerce_arg(e, arr_sort); } else { sort* dom = get_array_domain(e_sort, 0); @@ -2297,6 +2889,7 @@ expr_ref tptp_parser::parse_term() { } expr_ref tptp_parser::parse_formula(bool is_boolean) { + rec_guard g(*this); return parse_expr(PREC_IFF, true, is_boolean); } @@ -2335,16 +2928,48 @@ static unsigned read_tptp_stream(std::istream& in, char const* current_file) { register_on_timeout_proc(on_timeout); try { cmd_context ctx; - ctx.set_solver_factory(mk_smt_strategic_solver_factory()); tptp_parser p(ctx); p.parse_input(in, current_file ? current_file : "."); + p.assert_distinct_objects(); + + ctx.set_solver_factory(mk_smt_strategic_solver_factory()); + + // Optional: dump the parsed goal as an SMT-LIB2 benchmark (env Z3_TPTP_DUMP_SMT2 + // gives the output file path). Used to produce SMTLIB versions of TPTP instances. + if (char const* dump_path = getenv("Z3_TPTP_DUMP_SMT2")) { + std::ofstream dout(dump_path); + if (dout) { + ast_manager& m = ctx.m(); + dout << "; Auto-generated from TPTP input: " + << (current_file ? current_file : "?") << "\n"; + dout << "(set-logic ALL)\n"; + decl_collector decls(m); + for (expr* a : ctx.assertions()) + decls.visit(a); + for (sort* s : decls.get_sorts()) + if (m.is_uninterp(s) && s->get_num_parameters() == 0) + dout << "(declare-sort " << s->get_name() << " 0)\n"; + ctx.display_smt2_benchmark(dout, ctx.assertions().size(), ctx.assertions().data()); + } + } // Suppress default check-sat output; TPTP frontend reports SZS status explicitly. std::ostringstream sink; scoped_regular_stream scoped_stream(ctx, sink); TRACE(parser, ctx.get_solver()->display(tout)); ctx.check_sat(0, nullptr); + // A value-indexed type family ("T > $tType") is a dependent type that our + // encoding approximates unsoundly (a universe element stands in for a type). + // Neither an unsat (Theorem/Unsatisfiable) nor a sat (CounterSatisfiable/ + // Satisfiable) verdict can be trusted, so downgrade both to GaveUp. + if (p.has_dependent_type() && + (ctx.cs_state() == cmd_context::css_unsat || ctx.cs_state() == cmd_context::css_sat)) { + std::cout << "% SZS status GaveUp\n"; + std::cout << "% SZS reason problem declares a dependent type family " + "(T > $tType); verdict is not certified\n"; + } + else switch (ctx.cs_state()) { case cmd_context::css_unsat: if (p.has_conjecture()) report_szs_status("Theorem", p.expected_status()); diff --git a/src/math/grobner/pdd_simplifier.cpp b/src/math/grobner/pdd_simplifier.cpp index 8cc47c21e6..df12638d89 100644 --- a/src/math/grobner/pdd_simplifier.cpp +++ b/src/math/grobner/pdd_simplifier.cpp @@ -494,7 +494,7 @@ namespace dd { hash(unsigned_vector& vars):vars(vars) {} bool operator()(mon const& m) const { return unsigned_ptr_hash(vars.data() + m.offset, m.sz, 1); - }; + } }; struct eq { unsigned_vector& vars; diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 9e9d1add14..8be0cca91b 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -63,6 +63,7 @@ namespace lp { unsigned_vector m_row_bounds_to_replay; u_dependency_manager m_dependencies; svector m_tmp_dependencies; + ptr_vector m_tmp_witnesses; u_dependency* m_crossed_bounds_deps = nullptr; lpvar m_crossed_bounds_column = null_lpvar; @@ -1132,6 +1133,24 @@ namespace lp { ex.push_back(ci); } + // Linearize the bound witnesses of all fixed columns in the row together, so the + // mark bits walk each dependency sub-DAG shared between columns only once. + void lar_solver::explain_fixed_in_row(unsigned row, explanation& ex) { + auto& witnesses = m_imp->m_tmp_witnesses; + witnesses.reset(); + for (auto const& c : get_row(row)) { + if (!column_is_fixed(c.var())) + continue; + const column& ul = m_imp->m_columns[c.var()]; + witnesses.push_back(ul.lower_bound_witness()); + witnesses.push_back(ul.upper_bound_witness()); + } + m_imp->m_tmp_dependencies.reset(); + m_imp->m_dependencies.linearize(witnesses, m_imp->m_tmp_dependencies); + for (auto ci : m_imp->m_tmp_dependencies) + ex.push_back(ci); + } + void lar_solver::remove_fixed_vars_from_base() { // this will allow to disable and restore the tracking of the touched rows flet f(get_core_solver().m_r_solver.m_touched_rows, nullptr); @@ -3006,4 +3025,3 @@ namespace lp { } } // namespace lp - diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 79c729e5d1..4588f1772f 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -521,6 +521,7 @@ public: } void explain_fixed_column(unsigned j, explanation& ex); + void explain_fixed_in_row(unsigned row, explanation& ex); u_dependency* join_deps(u_dependency* a, u_dependency *b) { return dep_manager().mk_join(a, b); } const constraint_set & constraints() const; void push(); diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 2568c51fbd..3df2fbf741 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -248,22 +248,16 @@ public: void explain_fixed_in_row(unsigned row, explanation& ex) { TRACE(eq, tout << lp().get_row(row) << std::endl); - for (const auto& c : lp().get_row(row)) - if (lp().column_is_fixed(c.var())) - lp().explain_fixed_column(c.var(), ex); + lp().explain_fixed_in_row(row, ex); } unsigned explain_fixed_in_row_and_get_base(unsigned row, explanation& ex) { - unsigned base = UINT_MAX; TRACE(eq, tout << lp().get_row(row) << std::endl); - for (const auto& c : lp().get_row(row)) { - if (lp().column_is_fixed(c.var())) { - lp().explain_fixed_column(c.var(), ex); - } - else if (lp().is_base(c.var())) { + lp().explain_fixed_in_row(row, ex); + unsigned base = UINT_MAX; + for (const auto& c : lp().get_row(row)) + if (!lp().column_is_fixed(c.var()) && lp().is_base(c.var())) base = c.var(); - } - } return base; } diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index d1ac780e84..fe0d403fba 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -267,7 +267,7 @@ namespace lp { unsigned j, const T &m, X &theta, bool &unlimited) { SASSERT(m > 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); - }; + } void get_bound_on_variable_and_update_leaving_precisely( unsigned j, vector &leavings, T m, X &t, diff --git a/src/math/lp/nla_types.h b/src/math/lp/nla_types.h index 89823e4dc3..a57ca15e6b 100644 --- a/src/math/lp/nla_types.h +++ b/src/math/lp/nla_types.h @@ -43,9 +43,9 @@ namespace nla { ineq(lpvar v, lp::lconstraint_kind cmp, rational const& r): m_cmp(cmp), m_term(v), m_rs(r) {} bool operator==(const ineq& a) const = delete; bool operator!=(const ineq& a) const = delete; - const lp::lar_term& term() const { return m_term; }; - lp::lconstraint_kind cmp() const { return m_cmp; }; - const rational& rs() const { return m_rs; }; + const lp::lar_term& term() const { return m_term; } + lp::lconstraint_kind cmp() const { return m_cmp; } + const rational& rs() const { return m_rs; } }; class lemma { diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index a890913c2d..945b9023dc 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -3511,4 +3511,4 @@ namespace algebraic_numbers { void manager::collect_statistics(statistics & st) const { m_imp->collect_statistics(st); } -}; +} diff --git a/src/math/polynomial/algebraic_numbers.h b/src/math/polynomial/algebraic_numbers.h index e60f8ea1a9..37c0559728 100644 --- a/src/math/polynomial/algebraic_numbers.h +++ b/src/math/polynomial/algebraic_numbers.h @@ -410,7 +410,7 @@ namespace algebraic_numbers { anum& operator=(basic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, BASIC); return *this; } anum& operator=(algebraic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, ROOT); return *this; } }; -}; +} typedef algebraic_numbers::manager anum_manager; typedef algebraic_numbers::manager::numeral anum; diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 1b06fb2b09..84825baeb8 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -8253,7 +8253,7 @@ namespace polynomial { p->display_smt2(out, m_imp->m_manager, proc); return out; } -}; +} polynomial::polynomial * convert(polynomial::manager & sm, polynomial::polynomial * p, polynomial::manager & tm, polynomial::var x, unsigned max_d) { diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 5774e6e132..9d0bcabcf3 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -36,7 +36,7 @@ class small_object_allocator; namespace algebraic_numbers { class anum; class manager; -}; +} namespace polynomial { typedef unsigned var; @@ -1065,7 +1065,7 @@ namespace polynomial { scoped_set_zp(manager & _m, uint64_t p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } ~scoped_set_zp() { if (m_modular) m.set_zp(m_p); else m.set_z(); } }; -}; +} typedef polynomial::polynomial_ref polynomial_ref; typedef polynomial::polynomial_ref_vector polynomial_ref_vector; diff --git a/src/math/polynomial/polynomial_cache.cpp b/src/math/polynomial/polynomial_cache.cpp index 7d3a15ded6..095027bae4 100644 --- a/src/math/polynomial/polynomial_cache.cpp +++ b/src/math/polynomial/polynomial_cache.cpp @@ -256,4 +256,4 @@ namespace polynomial { dealloc(m_imp); m_imp = alloc(imp, _m); } -}; +} diff --git a/src/math/polynomial/polynomial_cache.h b/src/math/polynomial/polynomial_cache.h index a27abf42d1..ae8fa0ed82 100644 --- a/src/math/polynomial/polynomial_cache.h +++ b/src/math/polynomial/polynomial_cache.h @@ -40,4 +40,4 @@ namespace polynomial { void factor(polynomial const * p, polynomial_ref_vector & distinct_factors); void reset(); }; -}; +} diff --git a/src/math/polynomial/polynomial_primes.h b/src/math/polynomial/polynomial_primes.h index ea2baf0dcc..4c9e05e778 100644 --- a/src/math/polynomial/polynomial_primes.h +++ b/src/math/polynomial/polynomial_primes.h @@ -66,5 +66,5 @@ namespace polynomial { }; #endif -}; +} diff --git a/src/math/polynomial/polynomial_var2value.h b/src/math/polynomial/polynomial_var2value.h index 11e8c3bb8e..2897e74149 100644 --- a/src/math/polynomial/polynomial_var2value.h +++ b/src/math/polynomial/polynomial_var2value.h @@ -43,6 +43,6 @@ namespace polynomial { } }; -}; +} diff --git a/src/math/polynomial/rpolynomial.cpp b/src/math/polynomial/rpolynomial.cpp index 67b8825253..17a3be50d4 100644 --- a/src/math/polynomial/rpolynomial.cpp +++ b/src/math/polynomial/rpolynomial.cpp @@ -789,4 +789,4 @@ namespace rpolynomial { } #endif -}; +} diff --git a/src/math/polynomial/rpolynomial.h b/src/math/polynomial/rpolynomial.h index 2a5123a031..ab04c99d63 100644 --- a/src/math/polynomial/rpolynomial.h +++ b/src/math/polynomial/rpolynomial.h @@ -175,7 +175,7 @@ namespace rpolynomial { return out; } }; -}; +} typedef rpolynomial::polynomial_ref rpolynomial_ref; typedef rpolynomial::polynomial_ref_vector rpolynomial_ref_vector; diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index a30691c9df..7ce6aab5a6 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -3142,4 +3142,4 @@ namespace upolynomial { } return out; } -}; +} diff --git a/src/math/polynomial/upolynomial.h b/src/math/polynomial/upolynomial.h index de29a1cdf4..135422b94f 100644 --- a/src/math/polynomial/upolynomial.h +++ b/src/math/polynomial/upolynomial.h @@ -917,4 +917,4 @@ namespace upolynomial { std::ostream& display(std::ostream & out, upolynomial_sequence const & seq, char const * var_name = "x") const; }; -}; +} diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 1ab95def35..34bd83b7ad 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -1299,4 +1299,4 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, return factor_square_free(upm, f, fs, 1, params); } -}; // end upolynomial namespace +} // end upolynomial namespace diff --git a/src/math/polynomial/upolynomial_factorization.h b/src/math/polynomial/upolynomial_factorization.h index 3842665bd1..14ec508c3b 100644 --- a/src/math/polynomial/upolynomial_factorization.h +++ b/src/math/polynomial/upolynomial_factorization.h @@ -90,5 +90,5 @@ namespace upolynomial { That is, the factors of f are inserted as factors of degree k into fs. */ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, unsigned k, factor_params const & ps = factor_params()); -}; +} diff --git a/src/math/polynomial/upolynomial_factorization_int.h b/src/math/polynomial/upolynomial_factorization_int.h index f47610b65d..45f0204441 100644 --- a/src/math/polynomial/upolynomial_factorization_int.h +++ b/src/math/polynomial/upolynomial_factorization_int.h @@ -416,5 +416,5 @@ namespace upolynomial { } } }; -}; +} diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 4ba1c11fa7..427070a85d 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -6486,7 +6486,7 @@ namespace realclosure { { return m_imp->get_sign_condition_coefficient(a, i, j); } -}; +} void pp(realclosure::manager::imp * imp, realclosure::polynomial const & p, realclosure::extension * ext) { imp->display_polynomial_expr(std::cout, p, ext, false, false); diff --git a/src/math/realclosure/realclosure.h b/src/math/realclosure/realclosure.h index a1fae3e2bf..b256ffd15b 100644 --- a/src/math/realclosure/realclosure.h +++ b/src/math/realclosure/realclosure.h @@ -317,7 +317,7 @@ namespace realclosure { void * data() { return m_value; } static num mk(void * ptr) { num r; r.m_value = reinterpret_cast(ptr); return r; } }; -}; +} typedef realclosure::manager rcmanager; typedef rcmanager::numeral rcnumeral; diff --git a/src/math/simplex/simplex.cpp b/src/math/simplex/simplex.cpp index 6174b81b35..30de88c543 100644 --- a/src/math/simplex/simplex.cpp +++ b/src/math/simplex/simplex.cpp @@ -74,4 +74,4 @@ namespace simplex { } } } -}; +} diff --git a/src/math/simplex/simplex.h b/src/math/simplex/simplex.h index 0405a59d0b..ad194ebe71 100644 --- a/src/math/simplex/simplex.h +++ b/src/math/simplex/simplex.h @@ -204,5 +204,5 @@ namespace simplex { void kernel(sparse_matrix& s, vector>& K); void kernel_ffe(sparse_matrix &s, vector> &K); -}; +} diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 69ed434ce6..f7adf424d6 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -1035,6 +1035,6 @@ namespace simplex { } -}; +} diff --git a/src/math/simplex/sparse_matrix.h b/src/math/simplex/sparse_matrix.h index 942873b5fa..90cd88d142 100644 --- a/src/math/simplex/sparse_matrix.h +++ b/src/math/simplex/sparse_matrix.h @@ -355,4 +355,4 @@ namespace simplex { typedef unsynch_mpq_inf_manager eps_manager; }; -}; +} diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index fd4e7b0c32..430310bc89 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -603,5 +603,5 @@ namespace simplex { -}; +} diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index d531f1bafd..51d7b753e0 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -271,4 +271,4 @@ namespace subpaving { return alloc(context_mpfx_wrapper, lim, m, qm, p, a); } -}; +} diff --git a/src/math/subpaving/subpaving.h b/src/math/subpaving/subpaving.h index b76f5e8313..0c5a76770d 100644 --- a/src/math/subpaving/subpaving.h +++ b/src/math/subpaving/subpaving.h @@ -116,6 +116,6 @@ context * mk_hwf_context(reslimit& lim, f2n & m, unsynch_mpq_manage context * mk_mpff_context(reslimit& lim, mpff_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); context * mk_mpfx_context(reslimit& lim, mpfx_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); -}; +} diff --git a/src/math/subpaving/subpaving_hwf.h b/src/math/subpaving/subpaving_hwf.h index f2378a73a4..49f2dbc5fa 100644 --- a/src/math/subpaving/subpaving_hwf.h +++ b/src/math/subpaving/subpaving_hwf.h @@ -42,5 +42,5 @@ public: context_hwf(reslimit& lim, f2n & m, params_ref const & p, small_object_allocator * a):context_t(lim, config_hwf(m), p, a) {} }; -}; +} diff --git a/src/math/subpaving/subpaving_mpf.h b/src/math/subpaving/subpaving_mpf.h index 213c3c94b6..bc50de6fdf 100644 --- a/src/math/subpaving/subpaving_mpf.h +++ b/src/math/subpaving/subpaving_mpf.h @@ -43,5 +43,5 @@ public: context_mpf(reslimit& lim, f2n & m, params_ref const & p, small_object_allocator * a):context_t(lim, config_mpf(m), p, a) {} }; -}; +} diff --git a/src/math/subpaving/subpaving_mpff.h b/src/math/subpaving/subpaving_mpff.h index 763195cb91..631293be0c 100644 --- a/src/math/subpaving/subpaving_mpff.h +++ b/src/math/subpaving/subpaving_mpff.h @@ -39,5 +39,5 @@ struct config_mpff { typedef context_t context_mpff; -}; +} diff --git a/src/math/subpaving/subpaving_mpfx.h b/src/math/subpaving/subpaving_mpfx.h index 9613aa124d..14611c13a5 100644 --- a/src/math/subpaving/subpaving_mpfx.h +++ b/src/math/subpaving/subpaving_mpfx.h @@ -39,5 +39,5 @@ struct config_mpfx { typedef context_t context_mpfx; -}; +} diff --git a/src/math/subpaving/subpaving_mpq.h b/src/math/subpaving/subpaving_mpq.h index 441fbe0663..7468672a82 100644 --- a/src/math/subpaving/subpaving_mpq.h +++ b/src/math/subpaving/subpaving_mpq.h @@ -37,5 +37,5 @@ struct config_mpq { typedef context_t context_mpq; -}; +} diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index 7300e3da3c..3a6081f409 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -845,5 +845,5 @@ public: void operator()(); }; -}; +} diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index b71b10faec..39f4a84f5b 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -1952,4 +1952,4 @@ bool context_t::check_invariant() const { } -}; +} diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 8422006677..76de5d6e9b 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -404,7 +404,18 @@ struct evaluator_cfg : public default_rewriter_cfg { polymorphism::substitution subst(m); polymorphism::util util(m); util.unify(f, m.poly_root(f), subst); - def = subst(def); + expr_ref d = subst(def); + // The polymorphic interpretation body may carry type variables that the + // instance/root unification does not fully resolve (e.g. when the body was + // built with type variables distinct from the root signature's, as happens + // for reified type constructors). If the substituted definition does not + // have the instance's range sort, it would produce an ill-sorted rewrite; + // treat the function as having no usable macro instead (sound: it is then + // evaluated as uninterpreted / by model completion). + if (!d || d->get_sort() != f->get_range()) + return false; + m_pinned.push_back(d); + def = d; SASSERT(def != nullptr); } diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 797ce0774c..067ac712ff 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -1360,4 +1360,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 1181cf82bb..3a9bdcf340 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -620,5 +620,5 @@ namespace datalog { void display_rel_decl(std::ostream& out, func_decl* f); }; -}; +} diff --git a/src/muz/base/dl_costs.cpp b/src/muz/base/dl_costs.cpp index 70688cd59c..35eaddce98 100644 --- a/src/muz/base/dl_costs.cpp +++ b/src/muz/base/dl_costs.cpp @@ -157,4 +157,4 @@ namespace datalog { } } -}; +} diff --git a/src/muz/base/dl_costs.h b/src/muz/base/dl_costs.h index ea3efcda99..a4c681af48 100644 --- a/src/muz/base/dl_costs.h +++ b/src/muz/base/dl_costs.h @@ -106,6 +106,6 @@ namespace datalog { void start(accounted_object *); void finish() { start(nullptr); } }; -}; +} diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 0824c84cf5..b23786020c 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -1084,6 +1084,6 @@ namespace datalog { -}; +} diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 87c2637a9b..e5126c778f 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -373,7 +373,7 @@ namespace datalog { This possibly returns a ";"-separated list of names. */ - symbol const& name() const { return m_name; } ; + symbol const& name() const { return m_name; } unsigned hash() const; @@ -386,6 +386,6 @@ namespace datalog { unsigned operator()(const rule * r) const; }; -}; +} diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index d621e1b24b..4e0572c978 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -709,4 +709,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index 4afacacf06..be694af461 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -281,5 +281,5 @@ namespace datalog { -}; +} diff --git a/src/muz/base/dl_rule_subsumption_index.cpp b/src/muz/base/dl_rule_subsumption_index.cpp index f3fb545b67..cf41c37f20 100644 --- a/src/muz/base/dl_rule_subsumption_index.cpp +++ b/src/muz/base/dl_rule_subsumption_index.cpp @@ -80,5 +80,5 @@ namespace datalog { return false; } -}; +} diff --git a/src/muz/base/dl_rule_subsumption_index.h b/src/muz/base/dl_rule_subsumption_index.h index 3783be3dc3..5d321fe7aa 100644 --- a/src/muz/base/dl_rule_subsumption_index.h +++ b/src/muz/base/dl_rule_subsumption_index.h @@ -56,6 +56,6 @@ namespace datalog { bool is_subsumed(app * query); }; -}; +} diff --git a/src/muz/base/dl_rule_transformer.cpp b/src/muz/base/dl_rule_transformer.cpp index bcdcc6b5bb..4342e3564a 100644 --- a/src/muz/base/dl_rule_transformer.cpp +++ b/src/muz/base/dl_rule_transformer.cpp @@ -148,4 +148,4 @@ namespace datalog { -}; +} diff --git a/src/muz/base/dl_rule_transformer.h b/src/muz/base/dl_rule_transformer.h index c446593bdd..9ac935357a 100644 --- a/src/muz/base/dl_rule_transformer.h +++ b/src/muz/base/dl_rule_transformer.h @@ -110,6 +110,6 @@ namespace datalog { static void remove_duplicate_tails(app_ref_vector& tail, bool_vector& tail_neg); }; -}; +} diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 975d4e721b..81740cc86a 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -681,5 +681,5 @@ namespace datalog { stm<; diff --git a/src/muz/bmc/dl_bmc_engine.h b/src/muz/bmc/dl_bmc_engine.h index 05d5707a66..c1631a8319 100644 --- a/src/muz/bmc/dl_bmc_engine.h +++ b/src/muz/bmc/dl_bmc_engine.h @@ -67,7 +67,7 @@ namespace datalog { void compile(rule_set const& rules, expr_ref_vector& fmls, unsigned level); expr_ref compile_query(func_decl* query_pred, unsigned level); }; -}; +} diff --git a/src/muz/clp/clp_context.cpp b/src/muz/clp/clp_context.cpp index ccaf46702b..7683e4dbaa 100644 --- a/src/muz/clp/clp_context.cpp +++ b/src/muz/clp/clp_context.cpp @@ -222,4 +222,4 @@ namespace datalog { return m_imp->get_answer(); } -}; +} diff --git a/src/muz/clp/clp_context.h b/src/muz/clp/clp_context.h index 306baf3bd3..4be64b325a 100644 --- a/src/muz/clp/clp_context.h +++ b/src/muz/clp/clp_context.h @@ -38,5 +38,5 @@ namespace datalog { void display_certificate(std::ostream& out) const override; expr_ref get_answer() override; }; -}; +} diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index e692196f26..300edfe239 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -878,4 +878,4 @@ namespace datalog { expr_ref ddnf::get_answer() { return m_imp->get_answer(); } -}; +} diff --git a/src/muz/ddnf/ddnf.h b/src/muz/ddnf/ddnf.h index 6a93ef2305..e25b7a8d08 100644 --- a/src/muz/ddnf/ddnf.h +++ b/src/muz/ddnf/ddnf.h @@ -65,5 +65,5 @@ namespace datalog { void display(std::ostream& out) const; void display_statistics(std::ostream& out) const; }; -}; +} diff --git a/src/muz/fp/datalog_parser.h b/src/muz/fp/datalog_parser.h index e836cbaec8..fcf1a1327f 100644 --- a/src/muz/fp/datalog_parser.h +++ b/src/muz/fp/datalog_parser.h @@ -42,5 +42,5 @@ namespace datalog { virtual bool parse_directory(char const * path) = 0; }; -}; +} diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index 773b45813f..310e09fe6f 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -164,6 +164,6 @@ namespace datalog { unsigned_vector const& dst_eq, unsigned_vector const& neg_eq); }; -}; +} diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 9c14421850..2592d642ca 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -631,12 +631,12 @@ namespace datalog { class identity_mutator_fn : public mutator_fn { public: - void operator()(base_object & t) override {}; + void operator()(base_object & t) override {} }; class identity_intersection_filter_fn : public intersection_filter_fn { public: - void operator()(base_object & t, const base_object & neg) override {}; + void operator()(base_object & t, const base_object & neg) override {} }; class default_permutation_rename_fn : public transformer_fn { @@ -1258,5 +1258,5 @@ namespace datalog { expr_ref_vector & renaming_arg); -}; +} diff --git a/src/muz/rel/dl_bound_relation.cpp b/src/muz/rel/dl_bound_relation.cpp index 2a078d8f7e..417ae0cb90 100644 --- a/src/muz/rel/dl_bound_relation.cpp +++ b/src/muz/rel/dl_bound_relation.cpp @@ -676,6 +676,6 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h index 8f852f0ba4..f90d643246 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -168,6 +168,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_check_table.cpp b/src/muz/rel/dl_check_table.cpp index 0a6d900274..e036fdb117 100644 --- a/src/muz/rel/dl_check_table.cpp +++ b/src/muz/rel/dl_check_table.cpp @@ -435,5 +435,5 @@ namespace datalog { return result; } -}; +} diff --git a/src/muz/rel/dl_check_table.h b/src/muz/rel/dl_check_table.h index 144d0d6fc4..4e49bd4de9 100644 --- a/src/muz/rel/dl_check_table.h +++ b/src/muz/rel/dl_check_table.h @@ -129,5 +129,5 @@ namespace datalog { unsigned get_size_estimate_bytes() const override { return m_tocheck->get_size_estimate_bytes(); } }; - }; + } diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 106d1b7919..edb7598d68 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -279,6 +279,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp index a2e42f6402..bfbd22f4a3 100644 --- a/src/muz/rel/dl_external_relation.cpp +++ b/src/muz/rel/dl_external_relation.cpp @@ -449,4 +449,4 @@ namespace datalog { return alloc(negation_filter_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); } -}; +} diff --git a/src/muz/rel/dl_external_relation.h b/src/muz/rel/dl_external_relation.h index c8887eeedb..98fd74992e 100644 --- a/src/muz/rel/dl_external_relation.h +++ b/src/muz/rel/dl_external_relation.h @@ -147,5 +147,5 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 7f3806b91a..61f76c77d6 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -2372,4 +2372,4 @@ namespace datalog { bool_rewriter(m).mk_or(disjs.size(), disjs.data(), fml); } -}; +} diff --git a/src/muz/rel/dl_finite_product_relation.h b/src/muz/rel/dl_finite_product_relation.h index 324564469f..f602e37126 100644 --- a/src/muz/rel/dl_finite_product_relation.h +++ b/src/muz/rel/dl_finite_product_relation.h @@ -359,6 +359,6 @@ namespace datalog { void to_formula(expr_ref& fml) const override; }; -}; +} diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index a008c2b731..4a1da5a791 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -364,6 +364,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_interval_relation.cpp b/src/muz/rel/dl_interval_relation.cpp index 81c630ec6a..39ffdbfcb1 100644 --- a/src/muz/rel/dl_interval_relation.cpp +++ b/src/muz/rel/dl_interval_relation.cpp @@ -648,5 +648,5 @@ namespace datalog { return false; } -}; +} diff --git a/src/muz/rel/dl_interval_relation.h b/src/muz/rel/dl_interval_relation.h index 0bddec4cf8..857a3f3dfd 100644 --- a/src/muz/rel/dl_interval_relation.h +++ b/src/muz/rel/dl_interval_relation.h @@ -134,6 +134,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 9565a71436..67b67bbef5 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -885,5 +885,5 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/rel/dl_mk_explanations.h b/src/muz/rel/dl_mk_explanations.h index 33d5cc8eea..ba2bbe082f 100644 --- a/src/muz/rel/dl_mk_explanations.h +++ b/src/muz/rel/dl_mk_explanations.h @@ -79,6 +79,6 @@ namespace datalog { static expr* get_explanation(relation_base const& r); }; -}; +} diff --git a/src/muz/rel/dl_mk_similarity_compressor.cpp b/src/muz/rel/dl_mk_similarity_compressor.cpp index 77d106e0cf..39ebbf4344 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.cpp +++ b/src/muz/rel/dl_mk_similarity_compressor.cpp @@ -543,4 +543,4 @@ namespace datalog { reset(); return result; } -}; +} diff --git a/src/muz/rel/dl_mk_similarity_compressor.h b/src/muz/rel/dl_mk_similarity_compressor.h index 394e1a9e62..73ff15339c 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.h +++ b/src/muz/rel/dl_mk_similarity_compressor.h @@ -71,6 +71,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index de10c4f7f0..cf85321226 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -751,5 +751,5 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_mk_simple_joins.h b/src/muz/rel/dl_mk_simple_joins.h index 6ec66159cd..f4aacdaa9a 100644 --- a/src/muz/rel/dl_mk_simple_joins.h +++ b/src/muz/rel/dl_mk_simple_joins.h @@ -56,6 +56,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 7dd9056f6d..9884aea060 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -1128,7 +1128,7 @@ namespace datalog { } } -}; +} diff --git a/src/muz/rel/dl_product_relation.h b/src/muz/rel/dl_product_relation.h index 63c0004898..e8190a8301 100644 --- a/src/muz/rel/dl_product_relation.h +++ b/src/muz/rel/dl_product_relation.h @@ -184,6 +184,6 @@ namespace datalog { } }; -}; +} diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index dda2704626..ed0c37f4ff 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -1689,5 +1689,5 @@ namespace datalog { return res; } -}; +} diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 58d46347d2..3c480785ae 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -699,6 +699,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index b1e64bd648..19fc688d01 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -662,4 +662,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h index 0166bec981..71fc8a15a3 100644 --- a/src/muz/rel/dl_sieve_relation.h +++ b/src/muz/rel/dl_sieve_relation.h @@ -190,6 +190,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index b59260863c..8cca81d733 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -1404,5 +1404,5 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index c548e3ff06..34f05f4798 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -494,5 +494,5 @@ namespace datalog { bool knows_exact_size() const override { return true; } }; - }; + } diff --git a/src/muz/rel/dl_table.cpp b/src/muz/rel/dl_table.cpp index 62670254d3..36344f5697 100644 --- a/src/muz/rel/dl_table.cpp +++ b/src/muz/rel/dl_table.cpp @@ -292,5 +292,5 @@ namespace datalog { table_base::iterator bitvector_table::end() const { return mk_iterator(alloc(bv_iterator, *this, true)); } -}; +} diff --git a/src/muz/rel/dl_table.h b/src/muz/rel/dl_table.h index 96f68f44cb..becb61d964 100644 --- a/src/muz/rel/dl_table.h +++ b/src/muz/rel/dl_table.h @@ -144,6 +144,6 @@ namespace datalog { -}; +} diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index 4f51001769..c264872c7d 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -489,5 +489,5 @@ namespace datalog { } } -}; +} diff --git a/src/muz/rel/dl_table_relation.h b/src/muz/rel/dl_table_relation.h index bb6368d253..9ff0636283 100644 --- a/src/muz/rel/dl_table_relation.h +++ b/src/muz/rel/dl_table_relation.h @@ -126,6 +126,6 @@ namespace datalog { bool knows_exact_size() const override { return m_table->knows_exact_size(); } }; -}; +} diff --git a/src/muz/rel/dl_vector_relation.h b/src/muz/rel/dl_vector_relation.h index f659831fb3..3f1edd28ee 100644 --- a/src/muz/rel/dl_vector_relation.h +++ b/src/muz/rel/dl_vector_relation.h @@ -397,6 +397,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index c4b6a65b2d..41bd91e31e 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -789,4 +789,4 @@ namespace datalog { } return nullptr; } -}; +} diff --git a/src/muz/rel/karr_relation.h b/src/muz/rel/karr_relation.h index 33ce1ef984..1aee4595db 100644 --- a/src/muz/rel/karr_relation.h +++ b/src/muz/rel/karr_relation.h @@ -80,6 +80,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 20735cfcc0..4d963b1764 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -630,4 +630,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index 8d48d2d37d..62f7566b80 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -125,5 +125,5 @@ namespace datalog { lbool saturate() override; }; -}; +} diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index f7a47f0e0e..5c133596be 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -147,6 +147,6 @@ namespace datalog { void disable_fast_pass() { m_disable_fast_pass = true; } }; -}; +} diff --git a/src/muz/spacer/spacer_concretize.cpp b/src/muz/spacer/spacer_concretize.cpp index 9700af1497..d73b3f638e 100644 --- a/src/muz/spacer/spacer_concretize.cpp +++ b/src/muz/spacer/spacer_concretize.cpp @@ -36,7 +36,7 @@ struct proc { } } }; -}; // namespace pattern_var_marker_ns +} // namespace pattern_var_marker_ns namespace spacer { void pob_concretizer::mark_pattern_vars() { pattern_var_marker_ns::proc proc(m_arith, m_var_marks); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 2691421463..0440a0d1e9 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -38,7 +38,7 @@ Notes: namespace datalog { class rule_set; class context; -}; // namespace datalog +} // namespace datalog namespace spacer { diff --git a/src/muz/spacer/spacer_convex_closure.h b/src/muz/spacer/spacer_convex_closure.h index c3676ddf51..da794c4a2d 100644 --- a/src/muz/spacer/spacer_convex_closure.h +++ b/src/muz/spacer/spacer_convex_closure.h @@ -155,7 +155,7 @@ class convex_closure { void add_row(const vector &point) { SASSERT(point.size() == dims()); m_data.add_row(point); - }; + } bool operator()() { return this->compute(); } bool compute(); diff --git a/src/muz/spacer/spacer_farkas_learner.cpp b/src/muz/spacer/spacer_farkas_learner.cpp index 0fa1b74c63..3016b69fe9 100644 --- a/src/muz/spacer/spacer_farkas_learner.cpp +++ b/src/muz/spacer/spacer_farkas_learner.cpp @@ -99,7 +99,7 @@ bool farkas_learner::is_pure_expr(func_decl_set const& symbs, expr* e, ast_manag return false; } return true; -}; +} /** diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 0fa8ae932b..4653d62b91 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -327,4 +327,4 @@ void lemma_eq_generalizer::operator() (lemma_ref &lemma) { } -}; +} diff --git a/src/muz/spacer/spacer_mbc.cpp b/src/muz/spacer/spacer_mbc.cpp index 78c2799ec6..ee4eb0228f 100644 --- a/src/muz/spacer/spacer_mbc.cpp +++ b/src/muz/spacer/spacer_mbc.cpp @@ -66,7 +66,7 @@ public: } - void reset() {reset_partition();}; + void reset() {reset_partition();} void reset_partition() {m_current_part = UINT_MAX;} unsigned partition() {return m_current_part;} bool found_partition() {return m_current_part < UINT_MAX;} diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 383fda4183..eb4d780c98 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -845,4 +845,4 @@ namespace spacer { return res; } -}; +} diff --git a/src/muz/spacer/spacer_qe_project.h b/src/muz/spacer/spacer_qe_project.h index 37d0985406..b48b3aa321 100644 --- a/src/muz/spacer/spacer_qe_project.h +++ b/src/muz/spacer/spacer_qe_project.h @@ -43,5 +43,5 @@ namespace spacer_qe { void array_project_selects (model& model, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars); void array_project (model& model, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects = false); -}; +} diff --git a/src/muz/spacer/spacer_sym_mux.h b/src/muz/spacer/spacer_sym_mux.h index 4ddbeb3e44..549a25b21b 100644 --- a/src/muz/spacer/spacer_sym_mux.h +++ b/src/muz/spacer/spacer_sym_mux.h @@ -35,7 +35,7 @@ private: public: func_decl_ref m_main; func_decl_ref_vector m_variants; - sym_mux_entry(ast_manager &m) : m_main(m), m_variants(m) {}; + sym_mux_entry(ast_manager &m) : m_main(m), m_variants(m) {} }; typedef obj_map decl2entry_map; diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 27915b6c9a..fadfe04cfd 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -41,7 +41,7 @@ namespace spacer { public: unsat_core_learner(ast_manager& m, iuc_proof& pr) : - m(m), m_pr(pr), m_unsat_core(m) {}; + m(m), m_pr(pr), m_unsat_core(m) {} virtual ~unsat_core_learner(); ast_manager& get_manager() {return m;} diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 40060629d0..36500eb770 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -35,7 +35,7 @@ Revision History: namespace spacer { unsat_core_plugin::unsat_core_plugin(unsat_core_learner& ctx): - m(ctx.get_manager()), m_ctx(ctx) {}; + m(ctx.get_manager()), m_ctx(ctx) {} void unsat_core_plugin_lemma::compute_partial_core(proof* step) { SASSERT(m_ctx.is_a(step)); diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index b844cdd469..c327a1fdba 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -40,7 +40,7 @@ namespace spacer { class unsat_core_plugin_lemma : public unsat_core_plugin { public: - unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; + unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){} void compute_partial_core(proof* step) override; private: void add_lowest_split_to_core(proof* step) const; @@ -53,7 +53,7 @@ namespace spacer { bool use_constant_from_a=true) : unsat_core_plugin(learner), m_split_literals(split_literals), - m_use_constant_from_a(use_constant_from_a) {}; + m_use_constant_from_a(use_constant_from_a) {} void compute_partial_core(proof* step) override; private: bool m_split_literals; @@ -66,7 +66,7 @@ namespace spacer { class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { public: - unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {}; + unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {} void compute_partial_core(proof* step) override; void finalize() override; protected: @@ -79,7 +79,7 @@ namespace spacer { class unsat_core_plugin_farkas_lemma_bounded : public unsat_core_plugin_farkas_lemma_optimized { public: - unsat_core_plugin_farkas_lemma_bounded(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin_farkas_lemma_optimized(learner, m) {}; + unsat_core_plugin_farkas_lemma_bounded(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin_farkas_lemma_optimized(learner, m) {} void finalize() override; }; diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index a775a7033d..d92d7614ca 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -1306,7 +1306,7 @@ namespace tb { } return out << "unmatched instruction"; } -}; +} namespace datalog { @@ -1655,4 +1655,4 @@ namespace datalog { return m_imp->get_answer(); } -}; +} diff --git a/src/muz/tab/tab_context.h b/src/muz/tab/tab_context.h index d5bda040e2..4db6426230 100644 --- a/src/muz/tab/tab_context.h +++ b/src/muz/tab/tab_context.h @@ -39,5 +39,5 @@ namespace datalog { void display_certificate(std::ostream& out) const override; expr_ref get_answer() override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp index f0efe2f3ac..5e163f087d 100644 --- a/src/muz/transforms/dl_mk_array_blast.cpp +++ b/src/muz/transforms/dl_mk_array_blast.cpp @@ -333,6 +333,6 @@ namespace datalog { return rules.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_array_blast.h b/src/muz/transforms/dl_mk_array_blast.h index 12102af73e..04254275b0 100644 --- a/src/muz/transforms/dl_mk_array_blast.h +++ b/src/muz/transforms/dl_mk_array_blast.h @@ -69,6 +69,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/transforms/dl_mk_array_eq_rewrite.h b/src/muz/transforms/dl_mk_array_eq_rewrite.h index eabef4792f..62a9a4e0da 100644 --- a/src/muz/transforms/dl_mk_array_eq_rewrite.h +++ b/src/muz/transforms/dl_mk_array_eq_rewrite.h @@ -44,5 +44,5 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_array_instantiation.h b/src/muz/transforms/dl_mk_array_instantiation.h index 71924288f9..4b8d8395b9 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.h +++ b/src/muz/transforms/dl_mk_array_instantiation.h @@ -116,5 +116,5 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_backwards.cpp b/src/muz/transforms/dl_mk_backwards.cpp index a47d0aeebb..b848167026 100644 --- a/src/muz/transforms/dl_mk_backwards.cpp +++ b/src/muz/transforms/dl_mk_backwards.cpp @@ -73,4 +73,4 @@ namespace datalog { return result.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_backwards.h b/src/muz/transforms/dl_mk_backwards.h index 4d1522e021..76aab80af3 100644 --- a/src/muz/transforms/dl_mk_backwards.h +++ b/src/muz/transforms/dl_mk_backwards.h @@ -30,6 +30,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 9ca982776d..d6f07915db 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -334,4 +334,4 @@ namespace datalog { return (*m_impl)(source); } -}; +} diff --git a/src/muz/transforms/dl_mk_bit_blast.h b/src/muz/transforms/dl_mk_bit_blast.h index 3681ecf380..0f7da47680 100644 --- a/src/muz/transforms/dl_mk_bit_blast.h +++ b/src/muz/transforms/dl_mk_bit_blast.h @@ -31,6 +31,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_coalesce.cpp b/src/muz/transforms/dl_mk_coalesce.cpp index 97c4bb3aff..c7e3a1aede 100644 --- a/src/muz/transforms/dl_mk_coalesce.cpp +++ b/src/muz/transforms/dl_mk_coalesce.cpp @@ -194,6 +194,6 @@ namespace datalog { return rules.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_coalesce.h b/src/muz/transforms/dl_mk_coalesce.h index f94ce3465a..07962a006a 100644 --- a/src/muz/transforms/dl_mk_coalesce.h +++ b/src/muz/transforms/dl_mk_coalesce.h @@ -54,6 +54,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_filter_rules.cpp b/src/muz/transforms/dl_mk_filter_rules.cpp index d403f8b953..32b3f63ba5 100644 --- a/src/muz/transforms/dl_mk_filter_rules.cpp +++ b/src/muz/transforms/dl_mk_filter_rules.cpp @@ -166,4 +166,4 @@ namespace datalog { return m_result; } -}; +} diff --git a/src/muz/transforms/dl_mk_filter_rules.h b/src/muz/transforms/dl_mk_filter_rules.h index 3939c542ba..605fde256f 100644 --- a/src/muz/transforms/dl_mk_filter_rules.h +++ b/src/muz/transforms/dl_mk_filter_rules.h @@ -79,7 +79,7 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp index 1afb61febc..9d696b7729 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp @@ -615,4 +615,4 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.h b/src/muz/transforms/dl_mk_interp_tail_simplifier.h index f1757dbce7..4658399380 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.h +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.h @@ -102,6 +102,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 71370a0b50..669ea1f2cf 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -308,5 +308,5 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_karr_invariants.h b/src/muz/transforms/dl_mk_karr_invariants.h index 9ba579a603..e33ff851cc 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.h +++ b/src/muz/transforms/dl_mk_karr_invariants.h @@ -68,6 +68,6 @@ namespace datalog { }; -}; +} diff --git a/src/muz/transforms/dl_mk_loop_counter.cpp b/src/muz/transforms/dl_mk_loop_counter.cpp index a20224eb29..245ad0b2d2 100644 --- a/src/muz/transforms/dl_mk_loop_counter.cpp +++ b/src/muz/transforms/dl_mk_loop_counter.cpp @@ -153,4 +153,4 @@ namespace datalog { return result; } -}; +} diff --git a/src/muz/transforms/dl_mk_loop_counter.h b/src/muz/transforms/dl_mk_loop_counter.h index b2758df67a..d74a73ffe3 100644 --- a/src/muz/transforms/dl_mk_loop_counter.h +++ b/src/muz/transforms/dl_mk_loop_counter.h @@ -43,6 +43,6 @@ namespace datalog { rule_set * revert(rule_set const& source); }; -}; +} diff --git a/src/muz/transforms/dl_mk_magic_sets.cpp b/src/muz/transforms/dl_mk_magic_sets.cpp index 395aa0d693..f8f34827fd 100644 --- a/src/muz/transforms/dl_mk_magic_sets.cpp +++ b/src/muz/transforms/dl_mk_magic_sets.cpp @@ -375,5 +375,5 @@ namespace datalog { result->add_rule(back_to_goal_rule); return result.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_magic_sets.h b/src/muz/transforms/dl_mk_magic_sets.h index 3a8a92580d..4e40e057c1 100644 --- a/src/muz/transforms/dl_mk_magic_sets.h +++ b/src/muz/transforms/dl_mk_magic_sets.h @@ -128,6 +128,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_magic_symbolic.cpp b/src/muz/transforms/dl_mk_magic_symbolic.cpp index ed05d2247e..054abf5e7c 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.cpp +++ b/src/muz/transforms/dl_mk_magic_symbolic.cpp @@ -130,4 +130,4 @@ namespace datalog { return app_ref(m.mk_app(g, q->get_num_args(), q->get_args()), m); } -}; +} diff --git a/src/muz/transforms/dl_mk_magic_symbolic.h b/src/muz/transforms/dl_mk_magic_symbolic.h index ac29194bcc..1003b2e318 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.h +++ b/src/muz/transforms/dl_mk_magic_symbolic.h @@ -32,6 +32,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index b2ec2fb297..a12b230bc3 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -361,4 +361,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.h b/src/muz/transforms/dl_mk_quantifier_abstraction.h index 33c70c08b2..40669b02a3 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.h +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.h @@ -55,6 +55,6 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 9e567c902b..bc1af9c585 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -289,6 +289,6 @@ namespace datalog { } -}; +} diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.h b/src/muz/transforms/dl_mk_quantifier_instantiation.h index 716de11f02..c27058e30f 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.h +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.h @@ -65,6 +65,6 @@ namespace datalog { -}; +} diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 340b0ac569..94c174c1db 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -878,4 +878,4 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index c0693fde06..adab914e08 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -199,6 +199,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index b6178bb817..a20b1cbdc2 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -235,4 +235,4 @@ namespace datalog { return result; } -}; +} diff --git a/src/muz/transforms/dl_mk_scale.h b/src/muz/transforms/dl_mk_scale.h index fcbf4c2265..39ab3cdce2 100644 --- a/src/muz/transforms/dl_mk_scale.h +++ b/src/muz/transforms/dl_mk_scale.h @@ -45,6 +45,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index ecdf3ab23a..6cfb1e8add 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -854,5 +854,5 @@ namespace datalog { return result.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_slice.h b/src/muz/transforms/dl_mk_slice.h index 807c6dac4e..e619bc90b7 100644 --- a/src/muz/transforms/dl_mk_slice.h +++ b/src/muz/transforms/dl_mk_slice.h @@ -106,6 +106,6 @@ namespace datalog { obj_map const& get_predicates() { return m_predicates; } }; -}; +} diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index c71fddf9ee..c0e499d06e 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -357,4 +357,4 @@ namespace datalog { return res.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_subsumption_checker.h b/src/muz/transforms/dl_mk_subsumption_checker.h index 87c5c8f2e5..e2b21da694 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.h +++ b/src/muz/transforms/dl_mk_subsumption_checker.h @@ -86,6 +86,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_synchronize.cpp b/src/muz/transforms/dl_mk_synchronize.cpp index 81c01d7fcc..261768bf7a 100644 --- a/src/muz/transforms/dl_mk_synchronize.cpp +++ b/src/muz/transforms/dl_mk_synchronize.cpp @@ -373,4 +373,4 @@ namespace datalog { return rules; } -}; +} diff --git a/src/muz/transforms/dl_mk_synchronize.h b/src/muz/transforms/dl_mk_synchronize.h index 3f3657cae7..c81a3c9c6d 100644 --- a/src/muz/transforms/dl_mk_synchronize.h +++ b/src/muz/transforms/dl_mk_synchronize.h @@ -128,5 +128,5 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_unbound_compressor.cpp b/src/muz/transforms/dl_mk_unbound_compressor.cpp index 15b619ff85..161af7cea9 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.cpp +++ b/src/muz/transforms/dl_mk_unbound_compressor.cpp @@ -400,4 +400,4 @@ namespace datalog { } -}; +} diff --git a/src/muz/transforms/dl_mk_unbound_compressor.h b/src/muz/transforms/dl_mk_unbound_compressor.h index 63463dc5ce..9102837bf4 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.h +++ b/src/muz/transforms/dl_mk_unbound_compressor.h @@ -88,6 +88,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/muz/transforms/dl_mk_unfold.cpp b/src/muz/transforms/dl_mk_unfold.cpp index 6a1ae1535e..2d71aafcef 100644 --- a/src/muz/transforms/dl_mk_unfold.cpp +++ b/src/muz/transforms/dl_mk_unfold.cpp @@ -59,5 +59,5 @@ namespace datalog { return rules.detach(); } -}; +} diff --git a/src/muz/transforms/dl_mk_unfold.h b/src/muz/transforms/dl_mk_unfold.h index abba64c897..6687e7fadf 100644 --- a/src/muz/transforms/dl_mk_unfold.h +++ b/src/muz/transforms/dl_mk_unfold.h @@ -46,6 +46,6 @@ namespace datalog { rule_set * operator()(rule_set const & source) override; }; -}; +} diff --git a/src/nlsat/nlsat_assignment.h b/src/nlsat/nlsat_assignment.h index d96c8099e9..73d565142e 100644 --- a/src/nlsat/nlsat_assignment.h +++ b/src/nlsat/nlsat_assignment.h @@ -97,5 +97,5 @@ namespace nlsat { bool contains(var x) const override { return x != m_y && m_assignment.is_assigned(x); } anum const & operator()(var x) const override { return m_assignment.value(x); } }; -}; +} diff --git a/src/nlsat/nlsat_clause.cpp b/src/nlsat/nlsat_clause.cpp index 9543c44978..270617d057 100644 --- a/src/nlsat/nlsat_clause.cpp +++ b/src/nlsat/nlsat_clause.cpp @@ -49,4 +49,4 @@ namespace nlsat { return false; } -}; +} diff --git a/src/nlsat/nlsat_clause.h b/src/nlsat/nlsat_clause.h index 91467303cd..52afece639 100644 --- a/src/nlsat/nlsat_clause.h +++ b/src/nlsat/nlsat_clause.h @@ -66,5 +66,5 @@ namespace nlsat { typedef ptr_vector clause_vector; -}; +} diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index 6520754163..9f97332bb7 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -699,4 +699,4 @@ namespace nlsat { void evaluator::pop(unsigned num_scopes) { // do nothing } -}; +} diff --git a/src/nlsat/nlsat_evaluator.h b/src/nlsat/nlsat_evaluator.h index d2db3f41a6..2ea5bdc4db 100644 --- a/src/nlsat/nlsat_evaluator.h +++ b/src/nlsat/nlsat_evaluator.h @@ -57,5 +57,5 @@ namespace nlsat { void pop(unsigned num_scopes); }; -}; +} diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index d9a0bf131b..0827af809e 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1784,7 +1784,7 @@ namespace nlsat { m_imp->test_root_literal(k, y, i, p, result); } -}; +} #ifdef Z3DEBUG #include void pp(nlsat::explain::imp & ex, unsigned num, nlsat::literal const * ls) { diff --git a/src/nlsat/nlsat_explain.h b/src/nlsat/nlsat_explain.h index 60a7c53e18..44279e8bba 100644 --- a/src/nlsat/nlsat_explain.h +++ b/src/nlsat/nlsat_explain.h @@ -108,4 +108,4 @@ namespace nlsat { void test_root_literal(atom::kind k, var y, unsigned i, poly* p, scoped_literal_vector & result); }; -}; +} diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 160c8afb66..580aae781a 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -794,4 +794,4 @@ namespace nlsat { out << "*"; return out; } -}; +} diff --git a/src/nlsat/nlsat_interval_set.h b/src/nlsat/nlsat_interval_set.h index 263ab8a103..4efd0c3678 100644 --- a/src/nlsat/nlsat_interval_set.h +++ b/src/nlsat/nlsat_interval_set.h @@ -118,5 +118,5 @@ namespace nlsat { return out; } -}; +} diff --git a/src/nlsat/nlsat_justification.h b/src/nlsat/nlsat_justification.h index d9567ebf93..55501a8aff 100644 --- a/src/nlsat/nlsat_justification.h +++ b/src/nlsat/nlsat_justification.h @@ -106,5 +106,5 @@ namespace nlsat { a.deallocate(obj_sz, ptr); } } -}; +} diff --git a/src/nlsat/nlsat_scoped_literal_vector.h b/src/nlsat/nlsat_scoped_literal_vector.h index d67805c156..ee3a4acd9c 100644 --- a/src/nlsat/nlsat_scoped_literal_vector.h +++ b/src/nlsat/nlsat_scoped_literal_vector.h @@ -107,5 +107,5 @@ namespace nlsat { operator literal const &() const { return m_lit; } void neg() { m_lit.neg(); } }; -}; +} diff --git a/src/nlsat/nlsat_simplify.cpp b/src/nlsat/nlsat_simplify.cpp index e1c10d5f51..08e5c3d58b 100644 --- a/src/nlsat/nlsat_simplify.cpp +++ b/src/nlsat/nlsat_simplify.cpp @@ -826,4 +826,4 @@ namespace nlsat { (*m_imp)(); } -}; +} diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 6a656b46d4..074b159484 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -4784,4 +4784,4 @@ namespace nlsat { unsigned solver::lws_spt_threshold() const { return m_imp->m_lws_spt_threshold; } bool solver::lws_witness_subs_lc() const { return m_imp->m_lws_witness_subs_lc; } bool solver::lws_witness_subs_disc() const { return m_imp->m_lws_witness_subs_disc; } -}; +} diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index b6e0034733..21d9e42538 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -316,4 +316,4 @@ namespace nlsat { }; -}; +} diff --git a/src/nlsat/nlsat_types.cpp b/src/nlsat/nlsat_types.cpp index 42c41cec14..f2fe6f4287 100644 --- a/src/nlsat/nlsat_types.cpp +++ b/src/nlsat/nlsat_types.cpp @@ -67,4 +67,4 @@ namespace nlsat { return a1->m_kind == a2->m_kind && a1->m_x == a2->m_x && a1->m_i == a2->m_i && a1->m_p == a2->m_p; } -}; +} diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index be8f625c92..ee3b2935bf 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -26,7 +26,7 @@ Revision History: namespace algebraic_numbers { class anum; class manager; -}; +} namespace nlsat { #define NLSAT_VB_LVL 10 @@ -204,5 +204,5 @@ namespace nlsat { if (s == 0) return 0; return 1; } -}; +} diff --git a/src/opt/maxcore.h b/src/opt/maxcore.h index 283fee8506..f16904a21b 100644 --- a/src/opt/maxcore.h +++ b/src/opt/maxcore.h @@ -33,5 +33,5 @@ namespace opt { maxsmt_solver_base* mk_primal_dual_maxres(maxsat_context& c, unsigned id, vector& soft); -}; +} diff --git a/src/opt/maxlex.h b/src/opt/maxlex.h index fc30b1fd88..4cfa35fe49 100644 --- a/src/opt/maxlex.h +++ b/src/opt/maxlex.h @@ -26,5 +26,5 @@ namespace opt { maxsmt_solver_base* mk_maxlex(maxsat_context& c, unsigned id, vector& soft); -}; +} diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index d1d1506714..665b739783 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -380,12 +380,12 @@ namespace opt { params_ref& params() override { return m_params; } void enable_sls(bool force) override { } // no op symbol const& maxsat_engine() const override { return m_maxsat_engine; } - void get_base_model(model_ref& _m) override { _m = m_model; }; + void get_base_model(model_ref& _m) override { _m = m_model; } smt::context& smt_context() override { throw default_exception("stand-alone maxsat context does not support wmax"); } unsigned num_objectives() override { return 1; } - bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; }; + bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; } void set_model(model_ref& _m) override { m_model = _m; } void model_updated(model* mdl) override { } // no-op rational adjust(unsigned id, rational const& r) override { @@ -419,4 +419,4 @@ namespace opt { } return r; } -}; +} diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 7e75cde450..ca73437d5d 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -211,5 +211,5 @@ namespace opt { model_ref get_model() { return m_model; } }; -}; +} diff --git a/src/opt/opt_cores.cpp b/src/opt/opt_cores.cpp index 049a64da23..7948cdd502 100644 --- a/src/opt/opt_cores.cpp +++ b/src/opt/opt_cores.cpp @@ -394,4 +394,4 @@ namespace opt { } } -}; +} diff --git a/src/opt/opt_cores.h b/src/opt/opt_cores.h index 6dda34fd78..7ba4166913 100644 --- a/src/opt/opt_cores.h +++ b/src/opt/opt_cores.h @@ -68,4 +68,4 @@ namespace opt { void updt_params(params_ref& p); }; -}; +} diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp index 019a60b532..5133ac8c6c 100644 --- a/src/opt/opt_lns.cpp +++ b/src/opt/opt_lns.cpp @@ -269,4 +269,4 @@ namespace opt { return r; } -}; +} diff --git a/src/opt/opt_lns.h b/src/opt/opt_lns.h index 1bc27f9b13..4dc24d05c6 100644 --- a/src/opt/opt_lns.h +++ b/src/opt/opt_lns.h @@ -77,4 +77,4 @@ namespace opt { void set_conflicts(unsigned c) { m_max_conflicts = c; } unsigned climb(model_ref& mdl); }; -}; +} diff --git a/src/opt/opt_preprocess.cpp b/src/opt/opt_preprocess.cpp index 2e1b780707..3a4a712eb0 100644 --- a/src/opt/opt_preprocess.cpp +++ b/src/opt/opt_preprocess.cpp @@ -238,4 +238,4 @@ namespace opt { return false; return true; } -}; +} diff --git a/src/opt/opt_preprocess.h b/src/opt/opt_preprocess.h index 71e06eb2c6..21c9efde9c 100644 --- a/src/opt/opt_preprocess.h +++ b/src/opt/opt_preprocess.h @@ -40,4 +40,4 @@ namespace opt { preprocess(solver& s); bool operator()(vector& soft, rational& lower); }; -}; +} diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 586f22698b..eb8b4dd6cb 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -81,7 +81,7 @@ namespace opt { } void opt_solver::assert_expr_core(expr * t) { - m_last_model = nullptr; + m_model = nullptr; if (has_quantifiers(t)) { m_params.m_relevancy_lvl = 2; } @@ -178,7 +178,7 @@ namespace opt { verbose_stream().flush();); } lbool r; - m_last_model = nullptr; + m_model = nullptr; if (m_first && num_assumptions == 0 && m_context.get_scope_level() == 0) { r = m_context.setup_and_check(); } @@ -187,9 +187,9 @@ namespace opt { } r = adjust_result(r); if (r == l_true) { - m_context.get_model(m_last_model); - if (m_models.size() == 1) - m_models.set(0, m_last_model.get()); + m_context.get_model(m_model); + if (m_objective_models.size() == 1) + m_objective_models.set(0, m_model.get()); } m_first = false; if (dump_benchmarks()) { @@ -232,15 +232,15 @@ namespace opt { // Save results before popping inf_eps val = m_objective_values[i]; model_ref mdl; - if (m_models[i]) - mdl = m_models[i]; + if (m_objective_models[i]) + mdl = m_objective_models[i]; m_context.pop(1); // Restore the computed values after pop m_objective_values[i] = val; if (mdl) - m_models.set(i, mdl.get()); + m_objective_models.set(i, mdl.get()); // The baseline model may witness a greater value than the LP // optimizer returned, e.g. for non-linear objectives like mod @@ -260,8 +260,8 @@ namespace opt { expr_ref obj_val = (*baseline_model)(m_objective_terms.get(i)); if (a.is_numeral(obj_val, r) && inf_eps(r) > m_objective_values[i]) { m_objective_values[i] = inf_eps(r); - if (!m_models[i]) - m_models.set(i, baseline_model.get()); + if (!m_objective_models[i]) + m_objective_models.set(i, baseline_model.get()); expr* obj = m_objective_terms.get(i); if (a.is_int(obj)) blocker = a.mk_ge(obj, a.mk_numeral(r + 1, true)); @@ -301,7 +301,7 @@ namespace opt { bool opt_solver::maximize_objective(unsigned i, expr_ref& blocker) { smt::theory_var v = m_objective_vars[i]; bool has_shared = false; - m_last_model = nullptr; + m_model = nullptr; blocker = nullptr; // // compute an optimization hint. @@ -310,21 +310,37 @@ namespace opt { // relative to other theories. // inf_eps val = get_optimizer().maximize(v, blocker, has_shared); - m_context.get_model(m_last_model); + m_context.get_model(m_model); inf_eps val2; has_shared = true; TRACE(opt, tout << (has_shared?"has shared":"non-shared") << " " << val << " " << blocker << "\n"; - if (m_last_model) tout << *m_last_model << "\n";); - if (!m_models[i]) - m_models.set(i, m_last_model.get()); + if (m_model) tout << *m_model << "\n";); + if (!m_objective_models[i]) + m_objective_models.set(i, m_model.get()); TRACE(opt, tout << "maximize " << i << " " << val << " " << m_objective_values[i] << " " << blocker << "\n";); - if (val > m_objective_values[i]) { - m_objective_values[i] = val; - } + // + // Do NOT commit 'val' to m_objective_values yet: 'val' is only an + // optimization hint from the arithmetic relaxation. When the + // objective shares symbols with other theories (e.g. it occurs inside + // an uninterpreted function such as the auxiliary function used to + // encode large 'distinct' constraints) the hint can over-estimate the + // true optimum and may not be achievable by any model. Committing it + // prematurely and then failing validation (check_bound below) would + // leave m_objective_values holding an unachievable bound that callers + // such as optsmt::geometric_lex report as the optimum, together with a + // model that does not attain it (issue #10028). The value is only + // committed after it has been validated, or replaced by the value of + // an actual model in update_objective(). + // - if (!m_last_model) + if (!m_model) { + // Without a model there is nothing to validate 'val' against; keep + // the previous behavior of adopting the (possibly infinite) hint. + if (val > m_objective_values[i]) + m_objective_values[i] = val; return true; + } // // retrieve value of objective from current model and update @@ -332,7 +348,7 @@ namespace opt { // auto update_objective = [&]() { rational r; - expr_ref value = (*m_last_model)(m_objective_terms.get(i)); + expr_ref value = (*m_model)(m_objective_terms.get(i)); if (arith_util(m).is_numeral(value, r) && r > m_objective_values[i]) m_objective_values[i] = inf_eps(r); }; @@ -353,12 +369,12 @@ namespace opt { } else if (m_context.get_context().update_model(has_shared)) { TRACE(opt, tout << "updated\n";); - m_last_model = nullptr; - m_context.get_model(m_last_model); - if (!m_last_model) + m_model = nullptr; + m_context.get_model(m_model); + if (!m_model) return false; else if (!has_shared || val == current_objective_value(i)) - m_models.set(i, m_last_model.get()); + m_objective_models.set(i, m_model.get()); else if (!check_bound()) return false; } @@ -369,8 +385,8 @@ namespace opt { tout << "objective: " << mk_pp(m_objective_terms.get(i), m) << "\n"; tout << "maximal value: " << val << "\n"; tout << "new condition: " << blocker << "\n"; - if (m_models[i]) model_smt2_pp(tout << "update model:\n", m, *m_models[i], 0); - if (m_last_model) model_smt2_pp(tout << "last model:\n", m, *m_last_model, 0); + if (m_objective_models[i]) model_smt2_pp(tout << "update model:\n", m, *m_objective_models[i], 0); + if (m_model) model_smt2_pp(tout << "current model:\n", m, *m_model, 0); }); return true; } @@ -382,8 +398,8 @@ namespace opt { lbool is_sat = m_context.check(0, nullptr); is_sat = adjust_result(is_sat); if (is_sat == l_true) { - m_context.get_model(m_last_model); - m_models.set(i, m_last_model.get()); + m_context.get_model(m_model); + m_objective_models.set(i, m_model.get()); } pop_core(1); return is_sat == l_true; @@ -406,13 +422,13 @@ namespace opt { } void opt_solver::get_model_core(model_ref & m) { - if (m_last_model.get()) { - m = m_last_model.get(); + if (m_model.get()) { + m = m_model.get(); return; } - for (unsigned i = m_models.size(); i-- > 0; ) { - auto* mdl = m_models[i]; + for (unsigned i = m_objective_models.size(); i-- > 0; ) { + auto* mdl = m_objective_models[i]; if (mdl) { TRACE(opt, tout << "get " << i << "\n" << *mdl << "\n";); m = mdl; @@ -420,7 +436,7 @@ namespace opt { } } TRACE(opt, tout << "get last\n";); - m = m_last_model.get(); + m = m_model.get(); } proof * opt_solver::get_proof_core() { @@ -462,7 +478,7 @@ namespace opt { m_objective_vars.push_back(v); m_objective_values.push_back(inf_eps(rational::minus_one(), inf_rational())); m_objective_terms.push_back(term); - m_models.push_back(nullptr); + m_objective_models.push_back(nullptr); return v; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index d11e975202..4af90f7181 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -73,10 +73,10 @@ namespace opt { generic_model_converter& m_fm; progress_callback * m_callback; symbol m_logic; - model_ref m_last_model; + model_ref m_model; svector m_objective_vars; vector m_objective_values; - sref_vector m_models; + sref_vector m_objective_models; expr_ref_vector m_objective_terms; bool m_dump_benchmarks; static unsigned m_dump_count; @@ -171,7 +171,7 @@ namespace opt { void update_from_baseline_model(unsigned i, model_ref& baseline_model, expr_ref& blocker); inf_eps const & saved_objective_value(unsigned obj_index); inf_eps current_objective_value(unsigned obj_index); - model* get_model_idx(unsigned obj_index) { return m_models[obj_index]; } + model* get_model_idx(unsigned obj_index) { return m_objective_models[obj_index]; } bool was_unknown() const { return m_was_unknown; } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index f3ed1aaf91..5a2b4457b0 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -233,7 +233,7 @@ namespace opt { if (is_sat == l_true) m_s->display(tout); ); if (is_sat == l_true) { - m_s->maximize_objective(obj_index, bound); + bool bound_valid = m_s->maximize_objective(obj_index, bound); m_s->get_model(m_model); SASSERT(m_model); inf_eps obj = m_s->saved_objective_value(obj_index); @@ -250,7 +250,14 @@ namespace opt { else { ++steps; } - if (delta_per_step > rational::one() || (obj == last_objective && is_int)) { + // When maximize_objective could not validate its arithmetic + // hint (bound_valid == false), the blocker it produced refers to + // that unachievable hint and must not be used. 'obj' now holds + // the value of an actual model, so replace the blocker with a + // model-derived tightening so the search keeps making progress + // toward the true optimum instead of terminating prematurely + // (issue #10028). + if (!bound_valid || delta_per_step > rational::one() || (obj == last_objective && is_int)) { m_s->push(); ++num_scopes; bound = m_s->mk_ge(obj_index, obj + inf_eps(delta_per_step)); diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index b1198a7f90..385392a1dc 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -93,5 +93,5 @@ namespace opt { }; -}; +} diff --git a/src/opt/pb_sls.h b/src/opt/pb_sls.h index 6537574698..b511a45efa 100644 --- a/src/opt/pb_sls.h +++ b/src/opt/pb_sls.h @@ -44,5 +44,5 @@ namespace smt { }; -}; +} diff --git a/src/params/smt_params.cpp b/src/params/smt_params.cpp index a64075204c..bd58aeb311 100644 --- a/src/params/smt_params.cpp +++ b/src/params/smt_params.cpp @@ -28,6 +28,8 @@ void smt_params::updt_local_params(params_ref const & _p) { m_relevancy_lvl = p.relevancy(); m_ematching = p.ematching(); m_ho_matching = p.ho_matching(); + m_ho_matching_bound = p.ho_matching_bound(); + m_term_enumeration = p.term_enumeration(); m_induction = p.induction(); m_clause_proof = p.clause_proof(); m_phase_selection = static_cast(p.phase_selection()); diff --git a/src/params/smt_params.h b/src/params/smt_params.h index 7b5efa9919..3d696504ee 100644 --- a/src/params/smt_params.h +++ b/src/params/smt_params.h @@ -110,6 +110,8 @@ struct smt_params : public preprocessor_params, bool m_new_core2th_eq = true; bool m_ematching = true; bool m_ho_matching = false; + unsigned m_ho_matching_bound = 10000; + bool m_term_enumeration = true; bool m_induction = false; bool m_clause_proof = false; symbol m_proof_log; diff --git a/src/params/smt_params_helper.pyg b/src/params/smt_params_helper.pyg index d3f164f3bb..8dc181a2f9 100644 --- a/src/params/smt_params_helper.pyg +++ b/src/params/smt_params_helper.pyg @@ -11,6 +11,8 @@ def_module_params(module_name='smt', ('restricted_quasi_macros', BOOL, False, 'try to find universally quantified formulas that are restricted quasi-macros'), ('ematching', BOOL, True, 'E-Matching based quantifier instantiation'), ('ho_matching', BOOL, False, 'higher-order matching for quantifier instantiation'), + ('ho_matching_bound', UINT, 10000, 'per-problem expansion-step budget of the higher-order matching search; bounds the (undecidable) HO unification to guarantee termination'), + ('term_enumeration', BOOL, True, 'use term enumeration to populate instantiation sets for higher-order variables during model-based quantifier instantiation'), ('phase_selection', UINT, 3, 'phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences, 7 - theory'), ('phase_caching_on', UINT, 400, 'number of conflicts while phase caching is on'), ('phase_caching_off', UINT, 100, 'number of conflicts while phase caching is off'), diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index f7bfe6ed53..15f1721b16 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -3333,7 +3333,7 @@ namespace smt2 { }; void free_parser(parser * p) { dealloc(p); } -}; +} bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) { smt2::parser p(ctx, is, interactive, ps, filename); diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 3ab95ab40c..d6edcd0fb0 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -403,5 +403,5 @@ namespace smt2 { m_bend = 0; next(); } -}; +} diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index dd1aa04c06..fa37870ae3 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -104,6 +104,6 @@ namespace smt2 { char const * cached_str(unsigned begin, unsigned end); }; -}; +} diff --git a/src/qe/mbp/mbp_arith.h b/src/qe/mbp/mbp_arith.h index 1323032eba..936b08dbd1 100644 --- a/src/qe/mbp/mbp_arith.h +++ b/src/qe/mbp/mbp_arith.h @@ -51,5 +51,5 @@ namespace mbp { bool arith_project(model& model, app* var, expr_ref_vector& lits); -}; +} diff --git a/src/qe/mbp/mbp_arrays.cpp b/src/qe/mbp/mbp_arrays.cpp index 2c3e6ddf3b..d6daef7b9f 100644 --- a/src/qe/mbp/mbp_arrays.cpp +++ b/src/qe/mbp/mbp_arrays.cpp @@ -1500,4 +1500,4 @@ namespace mbp { } -}; +} diff --git a/src/qe/mbp/mbp_arrays.h b/src/qe/mbp/mbp_arrays.h index ed06ba78b3..1dced44c8c 100644 --- a/src/qe/mbp/mbp_arrays.h +++ b/src/qe/mbp/mbp_arrays.h @@ -40,5 +40,5 @@ namespace mbp { }; -}; +} diff --git a/src/qe/mbp/mbp_datatypes.h b/src/qe/mbp/mbp_datatypes.h index 28f93089d5..8f667e7b36 100644 --- a/src/qe/mbp/mbp_datatypes.h +++ b/src/qe/mbp/mbp_datatypes.h @@ -39,5 +39,5 @@ namespace mbp { }; -}; +} diff --git a/src/qe/mbp/mbp_euf.h b/src/qe/mbp/mbp_euf.h index 59515e9bd9..1be5cd3387 100644 --- a/src/qe/mbp/mbp_euf.h +++ b/src/qe/mbp/mbp_euf.h @@ -31,5 +31,5 @@ namespace mbp { }; -}; +} diff --git a/src/qe/mbp/mbp_plugin.h b/src/qe/mbp/mbp_plugin.h index 5e7dae8c78..67cf396287 100644 --- a/src/qe/mbp/mbp_plugin.h +++ b/src/qe/mbp/mbp_plugin.h @@ -69,7 +69,7 @@ namespace mbp { virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; } virtual family_id get_family_id() { return null_family_id; } - virtual bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; }; + virtual bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; } /** \brief project vars modulo model, return set of definitions for eliminated variables. diff --git a/src/qe/mbp/mbp_tg_plugins.h b/src/qe/mbp/mbp_tg_plugins.h index 3850f11ca1..671f3701ce 100644 --- a/src/qe/mbp/mbp_tg_plugins.h +++ b/src/qe/mbp/mbp_tg_plugins.h @@ -26,9 +26,9 @@ class mbp_tg_plugin { public: // iterate through all terms in m_tg and apply all theory MBP rules once // returns true if any rules were applied - virtual bool apply() { return false; }; + virtual bool apply() { return false; } virtual ~mbp_tg_plugin() = default; - virtual void use_model() { }; - virtual void get_new_vars(app_ref_vector*&) { }; - virtual family_id get_family_id() const { return null_family_id; }; + virtual void use_model() { } + virtual void get_new_vars(app_ref_vector*&) { } + virtual family_id get_family_id() const { return null_family_id; } }; diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index 7e68f33fbe..eda48e607f 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -2022,6 +2022,6 @@ namespace nlarith { void util::get_sign_branches(literal_set& lits, eval& ev, ptr_vector& branches) { m_imp->get_sign_branches(lits, ev, branches); } -}; +} diff --git a/src/qe/nlarith_util.h b/src/qe/nlarith_util.h index dccc4f606f..8f2137a155 100644 --- a/src/qe/nlarith_util.h +++ b/src/qe/nlarith_util.h @@ -143,5 +143,5 @@ namespace nlarith { }; -}; +} diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 263dad43cb..8e168e62fd 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -955,7 +955,7 @@ namespace qe { return alloc(nlqsat, m, m_mode, m_params); } }; -}; +} tactic * mk_nlqsat_tactic(ast_manager & m, params_ref const& p) { return alloc(qe::nlqsat, m, qe::qsat_t, p); diff --git a/src/qe/qe.h b/src/qe/qe.h index 2fd36596d9..6f07b157bf 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -367,6 +367,6 @@ namespace qe { }; -}; +} diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index ba8f5faa3b..aab03e9039 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -613,4 +613,4 @@ namespace qe { return pogo(pA, pB, itp); } -}; +} diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 93f7df88d4..18c33cb51a 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -156,4 +156,4 @@ namespace qe { lbool pogo(solver_factory& sf, expr* a, expr* b, expr_ref& itp); }; -}; +} diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 86234962c0..d5ca03096c 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -1503,7 +1503,7 @@ namespace qe { void qmax::collect_statistics(statistics& st) const { m_imp->m_qsat.collect_statistics(st); } -}; +} tactic * mk_qsat_tactic(ast_manager& m, params_ref const& p) { return alloc(qe::qsat, m, p, qe::qsat_sat); diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h index f6be01ef82..9f43048272 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -97,10 +97,10 @@ namespace dimacs { bool operator!=(iterator const& other) const { return m_eof != other.m_eof; } }; - iterator begin() { return iterator(*this, false); }; + iterator begin() { return iterator(*this, false); } iterator end() { return iterator(*this, true); } void set_read_theory(std::function& r) { m_read_theory_id = r; } }; -}; +} diff --git a/src/sat/sat_anf_simplifier.h b/src/sat/sat_anf_simplifier.h index 0f140d5ab4..8bd30bbe73 100644 --- a/src/sat/sat_anf_simplifier.h +++ b/src/sat/sat_anf_simplifier.h @@ -28,7 +28,7 @@ namespace dd { class pdd; class solver; -}; +} namespace sat { diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 0aed69d616..11a85b79e4 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -497,4 +497,4 @@ namespace sat { m_tr = 0; } -}; +} diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 20a561214e..7be980477e 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -106,5 +106,5 @@ namespace sat { inline void dec(unsigned c) { m_counter -= c; } }; -}; +} diff --git a/src/sat/sat_bcd.cpp b/src/sat/sat_bcd.cpp index 0b9792ad68..99e0bd4f8f 100644 --- a/src/sat/sat_bcd.cpp +++ b/src/sat/sat_bcd.cpp @@ -353,4 +353,4 @@ namespace sat { m_R.reset(); } -}; +} diff --git a/src/sat/sat_bcd.h b/src/sat/sat_bcd.h index 643a8b8ad4..52d11ba5ed 100644 --- a/src/sat/sat_bcd.h +++ b/src/sat/sat_bcd.h @@ -73,5 +73,5 @@ namespace sat { void operator()(union_find<>& uf); }; -}; +} diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 96ab78cb1a..9469f8431c 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -281,4 +281,4 @@ namespace sat { -}; +} diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index 8ee185f16a..a30231c7b0 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -87,5 +87,5 @@ namespace sat { void display(std::ostream& out) const; }; -}; +} diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index c59ce72891..6af39f4cd6 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -249,4 +249,4 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 0129febbf8..852508a123 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -198,5 +198,5 @@ namespace sat { std::ostream & operator<<(std::ostream & out, clause_wrapper const & c); -}; +} diff --git a/src/sat/sat_clause_set.cpp b/src/sat/sat_clause_set.cpp index c223009d6e..13e08eb54c 100644 --- a/src/sat/sat_clause_set.cpp +++ b/src/sat/sat_clause_set.cpp @@ -88,4 +88,4 @@ namespace sat { return true; } -}; +} diff --git a/src/sat/sat_clause_set.h b/src/sat/sat_clause_set.h index aa0be6b62d..1a2ad3e756 100644 --- a/src/sat/sat_clause_set.h +++ b/src/sat/sat_clause_set.h @@ -50,5 +50,5 @@ namespace sat { bool check_invariant() const; }; -}; +} diff --git a/src/sat/sat_clause_use_list.cpp b/src/sat/sat_clause_use_list.cpp index 347e49db99..b00e26e78e 100644 --- a/src/sat/sat_clause_use_list.cpp +++ b/src/sat/sat_clause_use_list.cpp @@ -54,4 +54,4 @@ namespace sat { m_clauses.shrink(m_j); } -}; +} diff --git a/src/sat/sat_clause_use_list.h b/src/sat/sat_clause_use_list.h index 14961a2236..63b5879568 100644 --- a/src/sat/sat_clause_use_list.h +++ b/src/sat/sat_clause_use_list.h @@ -134,5 +134,5 @@ namespace sat { } }; -}; +} diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 46b94b52c4..97abf11be5 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -230,4 +230,4 @@ namespace sat { st.update("sat elim literals", m_elim_literals); } -}; +} diff --git a/src/sat/sat_cleaner.h b/src/sat/sat_cleaner.h index 08d73029af..557b8a0d0b 100644 --- a/src/sat/sat_cleaner.h +++ b/src/sat/sat_cleaner.h @@ -48,5 +48,5 @@ namespace sat { void dec() { m_cleanup_counter--; } }; -}; +} diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 3dfb67f2a4..cf01d39eea 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -259,4 +259,4 @@ namespace sat { sat_params::collect_param_descrs(r); } -}; +} diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 83241fe88a..57076bf6ab 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -196,5 +196,5 @@ namespace sat { static void collect_param_descrs(param_descrs & d); }; -}; +} diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index f761ef9264..ea6ebd495b 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -306,4 +306,4 @@ namespace sat { } (*this)(roots, to_elim); } -}; +} diff --git a/src/sat/sat_elim_eqs.h b/src/sat/sat_elim_eqs.h index 8bfc2c4578..c5000f108b 100644 --- a/src/sat/sat_elim_eqs.h +++ b/src/sat/sat_elim_eqs.h @@ -47,5 +47,5 @@ namespace sat { void operator()(union_find<>& uf); }; -}; +} diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index b42cc33e21..0acfa4ea31 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -77,7 +77,7 @@ namespace sat { solver const& s() const { return *m_solver; } symbol const& name() const { return m_name; } - virtual void set_lookahead(lookahead* s) {}; + virtual void set_lookahead(lookahead* s) {} class scoped_drating { extension& ext; public: @@ -138,5 +138,5 @@ namespace sat { virtual std::string reason_unknown() { return "unknown"; } }; -}; +} diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index b10d243c23..54b0d63d79 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -221,4 +221,4 @@ namespace sat { VERIFY(check_disjoint_clauses()); return true; } -}; +} diff --git a/src/sat/sat_integrity_checker.h b/src/sat/sat_integrity_checker.h index bc7fecf68d..3d8ecd921d 100644 --- a/src/sat/sat_integrity_checker.h +++ b/src/sat/sat_integrity_checker.h @@ -42,4 +42,4 @@ namespace sat { bool check_disjoint_clauses() const; bool operator()() const; }; -}; +} diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index f83173aa7d..ecffa096fc 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -72,5 +72,5 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 87757ba59d..0aaaf6f04c 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -25,7 +25,7 @@ Notes: namespace pb { class solver; -}; +} namespace sat { diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 67136d79ab..d1b2d38f06 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -455,4 +455,4 @@ namespace sat { } } -}; +} diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index 170886aa69..1d44db51ac 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -153,4 +153,4 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 672e90185f..b6845c30c5 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -61,5 +61,5 @@ namespace sat { }; }; -}; +} diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 7d5c022ff1..8c9b897098 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -276,5 +276,5 @@ namespace sat { return copied; } -}; +} diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index 0fbf4f05d0..948eeaa3f0 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -112,5 +112,5 @@ namespace sat { bool copy_solver(solver& s); }; -}; +} diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index f1830623a3..b29e9513b1 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -322,4 +322,4 @@ namespace sat { void probing::reset_statistics() { m_num_assigned = 0; } -}; +} diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index 4b13d6afdd..a7eac7ba8b 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -91,5 +91,5 @@ namespace sat { void dec(unsigned c) { m_counter -= c; } }; -}; +} diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 8308a7ea59..21ceb3c6c5 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -282,4 +282,4 @@ namespace sat { sat_scc_params::collect_param_descrs(d); } -}; +} diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index af239c53d9..5b2f0dd260 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -65,5 +65,5 @@ namespace sat { int get_right(literal l) const { return m_big.get_right(l); } bool connected(literal u, literal v) const { return m_big.connected(u, v); } }; -}; +} diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 18e6288208..79c8a723c6 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -2148,4 +2148,4 @@ namespace sat { m_num_bca = 0; m_num_ate = 0; } -}; +} diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index e32c52e4a1..0dd85c6b85 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -250,5 +250,5 @@ namespace sat { bool need_cleanup() const { return m_need_cleanup; } }; -}; +} diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0a109bd0c5..634b09830e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4865,4 +4865,4 @@ namespace sat { return true; } -}; +} diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 66352387a2..a64b8fa614 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -48,7 +48,7 @@ Revision History: namespace pb { class solver; -}; +} namespace sat { @@ -895,4 +895,4 @@ namespace sat { std::ostream & operator<<(std::ostream & out, mk_stat const & stat); -}; +} diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h index cc0e6e0233..905f9739fd 100644 --- a/src/sat/sat_solver_core.h +++ b/src/sat/sat_solver_core.h @@ -49,7 +49,7 @@ namespace sat { // optional support for user-scopes. Not relevant for sat_tactic integration. // it is only relevant for incremental mode SAT, which isn't wrapped (yet) virtual void user_push() { throw default_exception("optional API not supported"); } - virtual void user_pop(unsigned num_scopes) {}; + virtual void user_pop(unsigned num_scopes) {} virtual unsigned num_user_scopes() const { return 0;} virtual unsigned num_scopes() const { return 0; } @@ -58,5 +58,5 @@ namespace sat { virtual extension* get_extension() const { return nullptr; } virtual void set_extension(extension* e) { if (e) throw default_exception("optional API not supported"); } }; -}; +} diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index b027d4f2e1..ce24521cae 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -106,7 +106,7 @@ namespace sat { int m_orig; const proof_hint* m_hint; public: - status(st s, int o, proof_hint const* ps = nullptr) : m_st(s), m_orig(o), m_hint(ps) {}; + status(st s, int o, proof_hint const* ps = nullptr) : m_st(s), m_orig(o), m_hint(ps) {} status(status const& s) : m_st(s.m_st), m_orig(s.m_orig), m_hint(s.m_hint) {} status(status&& s) noexcept { m_st = st::asserted; m_orig = -1; std::swap(m_st, s.m_st); std::swap(m_orig, s.m_orig); std::swap(m_hint, s.m_hint); } status& operator=(status const& other) { m_st = other.m_st; m_orig = other.m_orig; return *this; } @@ -170,7 +170,7 @@ namespace sat { }; -}; +} diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index 5573212f53..865a4b06dc 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -110,4 +110,4 @@ namespace sat { return out; } -}; +} diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 6d91434dba..4e44bbc1b1 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -125,5 +125,5 @@ namespace sat { std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist, extension* ext); void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist); -}; +} diff --git a/src/sat/smt/arith_value.cpp b/src/sat/smt/arith_value.cpp index fb66bdaefd..f6e1e68c79 100644 --- a/src/sat/smt/arith_value.cpp +++ b/src/sat/smt/arith_value.cpp @@ -142,4 +142,4 @@ namespace arith { #endif -}; +} diff --git a/src/sat/smt/arith_value.h b/src/sat/smt/arith_value.h index b858ff8965..89d7c69a36 100644 --- a/src/sat/smt/arith_value.h +++ b/src/sat/smt/arith_value.h @@ -49,4 +49,4 @@ namespace arith { expr_ref get_fixed(expr* e); #endif }; -}; +} diff --git a/src/sat/smt/bv_ackerman.h b/src/sat/smt/bv_ackerman.h index aab4053a28..259e1bfbf8 100644 --- a/src/sat/smt/bv_ackerman.h +++ b/src/sat/smt/bv_ackerman.h @@ -78,4 +78,4 @@ namespace bv { void propagate(); }; -}; +} diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index af3c4abe92..aeda79b5be 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -308,7 +308,7 @@ namespace bv { tmp = m.mk_or(literal2expr(b), tmp); xs.push_back(tmp); } - }; + } /** * The i'th bit in xs is 1 if the least significant bit of x is i or lower. @@ -324,7 +324,7 @@ namespace bv { tmp = m.mk_or(literal2expr(b), tmp); xs.push_back(tmp); } - }; + } /** * Check non-overflow of unsigned multiplication. diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 3ac6da3033..09299bbca6 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -521,7 +521,7 @@ namespace bv { } func_decl* f = m.mk_func_decl(th, sorts.size(), sorts.data(), proof); return m.mk_app(f, args); - }; + } void solver::asserted(literal l) { atom* a = get_bv2a(l.var()); diff --git a/src/sat/smt/euf_ackerman.h b/src/sat/smt/euf_ackerman.h index 846ddb8ae6..37ed814153 100644 --- a/src/sat/smt/euf_ackerman.h +++ b/src/sat/smt/euf_ackerman.h @@ -87,4 +87,4 @@ namespace euf { void propagate(); }; -}; +} diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 69017679c3..72fd6ebabb 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -576,7 +576,7 @@ namespace euf { return p.display(out); } -}; +} inline std::ostream& operator<<(std::ostream& out, euf::solver const& s) { return s.display(out); diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index 7f39cd5ed3..238c7d57cc 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -440,4 +440,4 @@ namespace fpa { } } -}; +} diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index 39094b9682..2b8468e16b 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -330,7 +330,7 @@ namespace intblast { } } return r; - }; + } bool solver::is_bv(sat::literal lit) { expr* e = ctx.bool_var2expr(lit.var()); diff --git a/src/sat/smt/pb_constraint.h b/src/sat/smt/pb_constraint.h index 4c6f69e077..15e885ae2d 100644 --- a/src/sat/smt/pb_constraint.h +++ b/src/sat/smt/pb_constraint.h @@ -100,7 +100,7 @@ namespace pb { virtual bool validate_unit_propagation(solver_interface const& s, literal alit) const = 0; - virtual bool is_watching(literal l) const { UNREACHABLE(); return false; }; + virtual bool is_watching(literal l) const { UNREACHABLE(); return false; } virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); } virtual void swap(unsigned i, unsigned j) noexcept { UNREACHABLE(); } virtual literal get_lit(unsigned i) const { UNREACHABLE(); return sat::null_literal; } diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 460a051ab2..fd91199bf7 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -3795,6 +3795,6 @@ namespace pb { return true; } -}; +} diff --git a/src/sat/smt/pb_solver.h b/src/sat/smt/pb_solver.h index 67c55c9d58..c73ad8f9ef 100644 --- a/src/sat/smt/pb_solver.h +++ b/src/sat/smt/pb_solver.h @@ -418,5 +418,5 @@ namespace pb { }; -}; +} diff --git a/src/sat/smt/q_queue.h b/src/sat/smt/q_queue.h index 3750ee31ba..256061aab7 100644 --- a/src/sat/smt/q_queue.h +++ b/src/sat/smt/q_queue.h @@ -26,7 +26,7 @@ Author: namespace euf { class solver; -}; +} namespace q { diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index 4bdfcf064f..df56bc1c98 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -169,4 +169,4 @@ namespace user_solver { euf::th_solver* clone(euf::solver& ctx) override; }; -}; +} diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index 2bbe7a4e1d..ba578b1850 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -278,5 +278,5 @@ namespace smt { out << "eq_adapter: #" << n1->get_owner_id() << " #" << n2->get_owner_id() << "\n"; } } -}; +} diff --git a/src/smt/arith_eq_adapter.h b/src/smt/arith_eq_adapter.h index 7b1c068761..b719d7e451 100644 --- a/src/smt/arith_eq_adapter.h +++ b/src/smt/arith_eq_adapter.h @@ -86,6 +86,6 @@ namespace smt { void collect_statistics(::statistics & st) const; void display_already_processed(std::ostream & out) const; }; -}; +} diff --git a/src/smt/dyn_ack.cpp b/src/smt/dyn_ack.cpp index 691bd7fc07..12fcc9754d 100644 --- a/src/smt/dyn_ack.cpp +++ b/src/smt/dyn_ack.cpp @@ -587,4 +587,4 @@ namespace smt { } #endif -}; +} diff --git a/src/smt/dyn_ack.h b/src/smt/dyn_ack.h index e04f78fd36..6d239d27b2 100644 --- a/src/smt/dyn_ack.h +++ b/src/smt/dyn_ack.h @@ -130,6 +130,6 @@ namespace smt { #endif }; -}; +} diff --git a/src/smt/fingerprints.cpp b/src/smt/fingerprints.cpp index d41e01573f..6a7d176965 100644 --- a/src/smt/fingerprints.cpp +++ b/src/smt/fingerprints.cpp @@ -165,4 +165,4 @@ namespace smt { #endif -}; +} diff --git a/src/smt/fingerprints.h b/src/smt/fingerprints.h index dc1863041e..93f6a115e7 100644 --- a/src/smt/fingerprints.h +++ b/src/smt/fingerprints.h @@ -76,6 +76,6 @@ namespace smt { bool slow_contains(void const * data, unsigned data_hash, unsigned num_args, enode * const * args) const; #endif }; -}; +} diff --git a/src/smt/mam.h b/src/smt/mam.h index e7051b3f76..758d9c684f 100644 --- a/src/smt/mam.h +++ b/src/smt/mam.h @@ -69,5 +69,5 @@ namespace smt { }; mam * mk_mam(context & ctx); -}; +} diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 905644354d..cb803d7559 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -518,5 +518,5 @@ namespace smt { #endif } -}; +} diff --git a/src/smt/qi_queue.h b/src/smt/qi_queue.h index 13878a158b..7ae92fd16b 100644 --- a/src/smt/qi_queue.h +++ b/src/smt/qi_queue.h @@ -101,6 +101,6 @@ namespace smt { m_on_binding = on_binding; } }; -}; +} diff --git a/src/smt/seq_axioms.h b/src/smt/seq_axioms.h index 525f6b3db3..f16ae6b55f 100644 --- a/src/smt/seq_axioms.h +++ b/src/smt/seq_axioms.h @@ -105,5 +105,5 @@ namespace smt { }; -}; +} diff --git a/src/smt/seq_offset_eq.h b/src/smt/seq_offset_eq.h index 669d63b7fd..ee308d5161 100644 --- a/src/smt/seq_offset_eq.h +++ b/src/smt/seq_offset_eq.h @@ -53,5 +53,5 @@ namespace smt { void pop_scope_eh(unsigned num_scopes); }; -}; +} diff --git a/src/smt/seq_regex.h b/src/smt/seq_regex.h index dd1c474b31..bba4d30eaa 100644 --- a/src/smt/seq_regex.h +++ b/src/smt/seq_regex.h @@ -214,4 +214,4 @@ namespace smt { }; -}; +} diff --git a/src/smt/smt_almost_cg_table.cpp b/src/smt/smt_almost_cg_table.cpp index f50f34dd6f..e97aa32d08 100644 --- a/src/smt/smt_almost_cg_table.cpp +++ b/src/smt/smt_almost_cg_table.cpp @@ -124,4 +124,4 @@ namespace smt { return result; } -}; +} diff --git a/src/smt/smt_almost_cg_table.h b/src/smt/smt_almost_cg_table.h index 6b0cc66526..f7b89af324 100644 --- a/src/smt/smt_almost_cg_table.h +++ b/src/smt/smt_almost_cg_table.h @@ -65,6 +65,6 @@ namespace smt { bool empty() const { return m_table.empty(); } }; -}; +} diff --git a/src/smt/smt_arith_value.cpp b/src/smt/smt_arith_value.cpp index 806598e76f..6c187b9482 100644 --- a/src/smt/smt_arith_value.cpp +++ b/src/smt/smt_arith_value.cpp @@ -169,4 +169,4 @@ namespace smt { return l_undef; return m_thr->check_lp_feasible(ineqs, lit_core, eq_core); } -}; +} diff --git a/src/smt/smt_arith_value.h b/src/smt/smt_arith_value.h index 7e351e43d5..3c2339887d 100644 --- a/src/smt/smt_arith_value.h +++ b/src/smt/smt_arith_value.h @@ -51,4 +51,4 @@ namespace smt { lbool check_lp_feasible(vector> &ineqs, literal_vector &lit_core, enode_pair_vector &eq_core); }; -}; +} diff --git a/src/smt/smt_b_justification.h b/src/smt/smt_b_justification.h index ae01a389d9..cbf399ef79 100644 --- a/src/smt/smt_b_justification.h +++ b/src/smt/smt_b_justification.h @@ -99,6 +99,6 @@ namespace smt { } typedef std::pair justified_literal; -}; +} diff --git a/src/smt/smt_bool_var_data.h b/src/smt/smt_bool_var_data.h index 68d7a8d45f..129a864897 100644 --- a/src/smt/smt_bool_var_data.h +++ b/src/smt/smt_bool_var_data.h @@ -131,6 +131,6 @@ namespace smt { m_atom = false; } }; -}; +} diff --git a/src/smt/smt_case_split_queue.h b/src/smt/smt_case_split_queue.h index 5c1b8c8ee3..1e503afdb9 100644 --- a/src/smt/smt_case_split_queue.h +++ b/src/smt/smt_case_split_queue.h @@ -52,6 +52,6 @@ namespace smt { }; case_split_queue * mk_case_split_queue(context & ctx, smt_params & p); -}; +} diff --git a/src/smt/smt_cg_table.cpp b/src/smt/smt_cg_table.cpp index 018a543c0b..a25b38aee9 100644 --- a/src/smt/smt_cg_table.cpp +++ b/src/smt/smt_cg_table.cpp @@ -258,5 +258,5 @@ namespace smt { return true; } -}; +} diff --git a/src/smt/smt_cg_table.h b/src/smt/smt_cg_table.h index 9c2baed11e..3b24ceccf1 100644 --- a/src/smt/smt_cg_table.h +++ b/src/smt/smt_cg_table.h @@ -216,6 +216,6 @@ namespace smt { bool check_invariant() const; }; -}; +} diff --git a/src/smt/smt_checker.cpp b/src/smt/smt_checker.cpp index d2c1758d35..ab25923111 100644 --- a/src/smt/smt_checker.cpp +++ b/src/smt/smt_checker.cpp @@ -182,7 +182,7 @@ namespace smt { m_bindings(nullptr) { } -}; +} diff --git a/src/smt/smt_checker.h b/src/smt/smt_checker.h index 3cd83a106d..7a69a12316 100644 --- a/src/smt/smt_checker.h +++ b/src/smt/smt_checker.h @@ -50,6 +50,6 @@ namespace smt { bool is_unsat(expr * n, unsigned num_bindings = 0, enode * const * bindings = nullptr); }; -}; +} diff --git a/src/smt/smt_clause.cpp b/src/smt/smt_clause.cpp index 061e1dd230..0c2e8617eb 100644 --- a/src/smt/smt_clause.cpp +++ b/src/smt/smt_clause.cpp @@ -126,4 +126,4 @@ namespace smt { return out << mk_pp(disj, m, 3); } -}; +} diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index 89d8f2d66b..eeb9375ef5 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -279,6 +279,6 @@ namespace smt { typedef ptr_vector clause_vector; typedef obj_hashtable clause_set; -}; +} diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index 324674a998..96e4a6d57c 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -291,6 +291,6 @@ namespace smt { } } -}; +} diff --git a/src/smt/smt_clause_proof.h b/src/smt/smt_clause_proof.h index 28191cfa25..7fa86671e0 100644 --- a/src/smt/smt_clause_proof.h +++ b/src/smt/smt_clause_proof.h @@ -94,6 +94,6 @@ namespace smt { }; std::ostream& operator<<(std::ostream& out, clause_proof::status st); -}; +} diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 6cb22e5058..c1bed6fdb8 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -1485,5 +1485,5 @@ namespace smt { return alloc(conflict_resolution, m, ctx, dack_manager, params, assigned_literals, watches); } -}; +} diff --git a/src/smt/smt_conflict_resolution.h b/src/smt/smt_conflict_resolution.h index 39f7c68d50..54e91ba941 100644 --- a/src/smt/smt_conflict_resolution.h +++ b/src/smt/smt_conflict_resolution.h @@ -276,6 +276,6 @@ namespace smt { ); -}; +} diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index fab8563bcd..b8e572513a 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4981,7 +4981,7 @@ namespace smt { m_model->add_rec_funs(); } -}; +} #ifdef Z3DEBUG diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 0a5ad1d5c7..f0105ff633 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1778,8 +1778,16 @@ namespace smt { void internalize_instance(expr * body, proof * pr, unsigned generation) { internalize_assertion(body, pr, generation); - if (relevancy()) + if (relevancy()) { + // if the instantiation creates a conflict, we backtrack immediately. + // to retain the conflict clause being relevant we mark it here. + // if the instantiation does not create a conflict, default relevancy propagation applies. + if (inconsistent() && is_app(body)) { + for (auto arg : *to_app(body)) + mark_as_relevant(arg); + } m_case_split_queue->internalize_instance_eh(body, generation); + } } unsigned get_unsat_core_size() const { @@ -1969,4 +1977,4 @@ namespace smt { std::ostream& operator<<(std::ostream& out, enode_pp const& p); -}; +} diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index e8f590e1a3..05b60ee625 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -420,5 +420,5 @@ namespace smt { } } -}; +} diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 8041099e59..10d6f624b8 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -786,5 +786,5 @@ namespace smt { IF_VERBOSE(2, verbose_stream() << str); } -}; +} diff --git a/src/smt/smt_context_stat.cpp b/src/smt/smt_context_stat.cpp index e1ff89c544..c01091e2b2 100644 --- a/src/smt/smt_context_stat.cpp +++ b/src/smt/smt_context_stat.cpp @@ -145,4 +145,4 @@ namespace smt { if (m_fparams.m_profile_res_sub) display_profile_res_sub(out); } -}; +} diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index 362bc81726..7e630f8a7d 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -351,5 +351,5 @@ namespace smt { get_enode()->m_func_decl_id = UINT_MAX; } -}; +} diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index b860c35aaf..1ba3d76b39 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -476,6 +476,6 @@ namespace smt { }; inline mk_pp pp(enode* n, ast_manager& m) { return mk_pp(n->get_expr(), m); } -}; +} diff --git a/src/smt/smt_eq_justification.h b/src/smt/smt_eq_justification.h index cc8b3ceb61..a8a3226c36 100644 --- a/src/smt/smt_eq_justification.h +++ b/src/smt/smt_eq_justification.h @@ -78,6 +78,6 @@ namespace smt { }; const eq_justification null_eq_justification(static_cast(nullptr)); -}; +} diff --git a/src/smt/smt_failure.h b/src/smt/smt_failure.h index 15890dd5bd..5ebc1fff61 100644 --- a/src/smt/smt_failure.h +++ b/src/smt/smt_failure.h @@ -35,5 +35,5 @@ namespace smt { QUANTIFIERS //!< Logical context contains universal quantifiers. }; -}; +} diff --git a/src/smt/smt_for_each_relevant_expr.cpp b/src/smt/smt_for_each_relevant_expr.cpp index e71a848a2b..5aac74b349 100644 --- a/src/smt/smt_for_each_relevant_expr.cpp +++ b/src/smt/smt_for_each_relevant_expr.cpp @@ -295,4 +295,4 @@ namespace smt { m_manager.is_label(n, pos, m_buffer); // copy symbols to buffer } -}; +} diff --git a/src/smt/smt_for_each_relevant_expr.h b/src/smt/smt_for_each_relevant_expr.h index 20be165c67..5fdb151736 100644 --- a/src/smt/smt_for_each_relevant_expr.h +++ b/src/smt/smt_for_each_relevant_expr.h @@ -35,7 +35,7 @@ namespace smt { unsigned count_at_labels_lit(expr* n, bool polarity); public: - check_at_labels(ast_manager& m) : m_manager(m) {}; + check_at_labels(ast_manager& m) : m_manager(m) {} /** \brief Check that 'n' as a formula contains at most one @ label within each and-or path. @@ -105,6 +105,6 @@ namespace smt { void operator()(expr * n) override; }; -}; +} diff --git a/src/smt/smt_implied_equalities.h b/src/smt/smt_implied_equalities.h index 8a063a5d85..6357cc952f 100644 --- a/src/smt/smt_implied_equalities.h +++ b/src/smt/smt_implied_equalities.h @@ -36,6 +36,6 @@ namespace smt { unsigned* class_ids); -}; +} diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 5a2eadbafc..3e8e5bb0fc 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1925,4 +1925,4 @@ namespace smt { } SASSERT(th->is_attached_to_var(n)); } -}; +} diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index 1ae6732173..03843f0a83 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -440,5 +440,5 @@ namespace smt { return m.mk_th_lemma(m_th_id, m.mk_or(lits), 0, nullptr, m_params.size(), m_params.data()); } -}; +} diff --git a/src/smt/smt_justification.h b/src/smt/smt_justification.h index 161ffe839f..14c1ce7483 100644 --- a/src/smt/smt_justification.h +++ b/src/smt/smt_justification.h @@ -423,6 +423,6 @@ namespace smt { char const * get_name() const override { return "theory-lemma"; } }; -}; +} diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 1e49a8d3ce..3453633f87 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -352,4 +352,4 @@ namespace smt { m_imp->m_kernel.user_propagate_initialize_value(var, value); } -}; +} diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 0a6faaa091..a5ddce96c3 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -346,4 +346,4 @@ namespace smt { context & get_context(); context const& get_context() const; }; -}; +} diff --git a/src/smt/smt_literal.cpp b/src/smt/smt_literal.cpp index 94ac5e5677..8ec28693dc 100644 --- a/src/smt/smt_literal.cpp +++ b/src/smt/smt_literal.cpp @@ -116,5 +116,5 @@ namespace smt { } -}; +} diff --git a/src/smt/smt_literal.h b/src/smt/smt_literal.h index 17ed9c6c47..cf773353d1 100644 --- a/src/smt/smt_literal.h +++ b/src/smt/smt_literal.h @@ -54,6 +54,6 @@ namespace smt { bool backward_subsumption(unsigned num_lits1, literal const * lits1, unsigned num_lits2, literal const * lits2); -}; +} diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index feccd7149e..56b8dfe759 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -222,7 +222,8 @@ namespace smt { expr * sk_term = m_model_finder.get_inv(q, i, sk_value, *cex, sk_term_gen); if (sk_term != nullptr) { TRACE(model_checker, tout << "Found inverse " << mk_pp(sk_term, m) << "\n";); - SASSERT(!m.is_model_value(sk_term)); + // get_inv may return a model value in polymorphic settings; + // this is handled downstream by get_type_compatible_term. max_generation = std::max(sk_term_gen, max_generation); sk_value = sk_term; } @@ -345,7 +346,8 @@ namespace smt { return false; TRACE(model_checker, tout << "skolems:\n" << sks << "\n";); - flet l(m_aux_context->get_fparams().m_array_fake_support, true); + flet l1(m_aux_context->get_fparams().m_array_fake_support, true); + flet l2(m_aux_context->get_fparams().m_preprocess, true); lbool r = m_aux_context->check(); TRACE(model_checker, tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";); @@ -362,7 +364,8 @@ namespace smt { unsigned num_new_instances = 0; while (true) { - flet l(m_aux_context->get_fparams().m_array_fake_support, true); + flet l1(m_aux_context->get_fparams().m_array_fake_support, true); + flet l2(m_aux_context->get_fparams().m_preprocess, true); lbool r = m_aux_context->check(); TRACE(model_checker, tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";); if (r != l_true) @@ -582,4 +585,4 @@ namespace smt { } } -}; +} diff --git a/src/smt/smt_model_checker.h b/src/smt/smt_model_checker.h index 3a8e816399..c0945689c7 100644 --- a/src/smt/smt_model_checker.h +++ b/src/smt/smt_model_checker.h @@ -104,5 +104,5 @@ namespace smt { void operator()(expr* e); }; -}; +} diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 4b461a59a1..c43028b40d 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -38,9 +38,11 @@ Revision History: #include "smt/smt_model_finder.h" #include "smt/smt_context.h" #include "tactic/tactic_exception.h" +#include "util/statistics.h" namespace smt { + namespace mf { // ----------------------------------- @@ -1167,6 +1169,7 @@ namespace smt { virtual char const* get_kind() const = 0; virtual bool is_equal(qinfo const* qi) const = 0; virtual void display(std::ostream& out) const { out << "[" << get_kind() << "]"; } + virtual void collect_statistics(::statistics &st) const {} // AUF fragment solver virtual void process_auf(quantifier* q, auf_solver& s, context* ctx) = 0; @@ -1379,10 +1382,15 @@ namespace smt { class ho_var : public qinfo { unsigned m_var_i; + unsigned m_ho_var_term_enum = 0; public: ho_var(ast_manager& m, unsigned i) : qinfo(m), m_var_i(i) { } + void collect_statistics(::statistics &st) const override { + st.update("mbqi.ho-var-term-enum", m_ho_var_term_enum); + } + char const *get_kind() const override { return "ho_var"; } @@ -1403,10 +1411,14 @@ namespace smt { } void populate_inst_sets(quantifier *q, auf_solver &s, context *ctx) override { + bool use_term_enum = ctx->get_fparams().m_term_enumeration; + if (!use_term_enum) + return; node *S = s.get_uvar(q, m_var_i); sort *srt = S->get_sort(); IF_VERBOSE(3, verbose_stream() << "ho_var::populate_inst_sets: " << q->get_id() << " " << mk_pp(srt, m) << "\n";); + term_enumeration tn(m); // Add ground terms of type S. // Add productions for functions in E-graph @@ -1415,6 +1427,7 @@ namespace smt { ast_mark visited; tn.add_production(m.mk_true()); tn.add_production(m.mk_false()); + for (enode *n : ctx->enodes()) { if (!ctx->is_relevant(n)) continue; @@ -1423,6 +1436,8 @@ namespace smt { TRACE(model_finder, tout << "inserting " << mk_pp(e, m) << " into inst set\n"); S->insert(e, ctx->get_generation(n)); } + else if (!use_term_enum) + continue; else if (is_app(e) && to_app(e)->get_decl()->is_skolem()) ; else if (is_uninterp_const(e)) { @@ -1438,7 +1453,7 @@ namespace smt { tn.add_production(f); } } - + unsigned max_count = 20; for (auto t : tn.enum_terms(srt)) { if (max_count == 0) @@ -1447,6 +1462,7 @@ namespace smt { unsigned generation = 0; // todo - inherited from sub-term of t? TRACE(model_finder, tout << "ho_var: adding term " << mk_ismt2_pp(t, m) << " to instantiation set of S" << std::endl;); + ++m_ho_var_term_enum; S->insert(t, generation); } } @@ -1772,6 +1788,11 @@ namespace smt { public: typedef ptr_vector::const_iterator macro_iterator; + void collect_statistics(::statistics &st) const { + for (auto *qi : m_qinfo_vect) + qi->collect_statistics(st); + } + static quantifier_ref mk_flat(ast_manager& m, quantifier* q) { if (has_quantifiers(q->get_expr())) { proof_ref pr(m); @@ -2414,6 +2435,13 @@ namespace smt { reset(); } + void model_finder::collect_statistics(::statistics & st) const { + // Retrieve the ho-var term-enumeration counters from the embedded + // qinfo objects (mf::ho_var) held by each registered quantifier_info. + for (auto const &[k, v] : m_q2info) + v->collect_statistics(st); + } + void model_finder::checkpoint() { checkpoint("model_finder"); } diff --git a/src/smt/smt_model_finder.h b/src/smt/smt_model_finder.h index 3b34e0192f..86fdd4878f 100644 --- a/src/smt/smt_model_finder.h +++ b/src/smt/smt_model_finder.h @@ -52,6 +52,7 @@ Revision History: #include "tactic/tactic_exception.h" class model_instantiation_set; +class statistics; namespace smt { class context; @@ -64,7 +65,7 @@ namespace smt { class hint_solver; class non_auf_macro_solver; class instantiation_set; - }; + } class model_finder : public quantifier2macro_infos { typedef mf::quantifier_analyzer quantifier_analyzer; @@ -122,6 +123,8 @@ namespace smt { quantifier_macro_info* operator()(quantifier* q) override; - }; -}; + void collect_statistics(::statistics & st) const; + + }; +} diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 8cf9508d6f..7ecbaca6c7 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -533,4 +533,4 @@ namespace smt { return m_model.get(); } -}; +} diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index fd99dc6d84..ffd1a1f963 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -240,7 +240,7 @@ namespace smt { } } }; -}; +} diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 9bd21238de..1a1e9a748b 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -28,6 +28,7 @@ Revision History: #include "smt/smt_quick_checker.h" #include "smt/mam.h" #include "smt/qi_queue.h" +#include "util/statistics.h" #include "util/obj_hashtable.h" namespace smt { @@ -218,9 +219,7 @@ namespace smt { STRACE(triggers, tout <<", Pat: "<< expr_ref(pat, m());); STRACE(causality, tout <<", Father:";); } - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); + for (auto [orig, substituted] : used_enodes) { (void) substituted; if (orig == nullptr) { STRACE(causality, tout << " #" << substituted->get_owner_id();); @@ -256,9 +255,8 @@ namespace smt { for (unsigned i = 0; i < num_bindings; ++i) { log_justification_to_root(out, bindings[i], already_visited, m_context, m()); } - for (auto n : used_enodes) { - enode *orig = std::get<0>(n); - enode *substituted = std::get<1>(n); + + for (auto [orig, substituted] : used_enodes) { if (orig != nullptr) { log_justification_to_root(out, orig, already_visited, m_context, m()); log_justification_to_root(out, substituted, already_visited, m_context, m()); @@ -576,6 +574,7 @@ namespace smt { void quantifier_manager::collect_statistics(::statistics & st) const { m_imp->m_qi_queue.collect_statistics(st); + m_imp->m_plugin->collect_statistics(st); } void quantifier_manager::reset_statistics() { @@ -623,6 +622,8 @@ namespace smt { vector>* m_used_enodes = nullptr; }; ho_match_state m_ho_state; + unsigned m_stat_ho_refine = 0; // number of times ho-matching refinement is invoked + unsigned m_stat_ho_instances = 0; // number of instances added via ho-matching public: default_qm_plugin(): m_qm(nullptr), @@ -649,7 +650,8 @@ namespace smt { if (m_fparams->m_ho_matching) { m_ho_matcher = alloc(euf::ho_matcher, m, m_context->get_trail_stack()); - std::function on_match = [&](euf::ho_subst& s) { + m_ho_matcher->set_max_iterations(m_fparams->m_ho_matching_bound); + std::function on_match = [this](euf::ho_subst& s) { on_ho_match(s); }; m_ho_matcher->set_on_match(on_match); @@ -676,12 +678,21 @@ namespace smt { << "\n" << binding << "\n";); if (binding.size() > q->get_num_decls()) { - var_subst sub(m); + // binding is indexed directly (binding[k] = value for var k), + // so the substitution must use direct (non-standard) order to + // resolve chained HO variable references; the sort guard below + // is checked with the matching order. + var_subst sub(m, false); bool change = true; while (change) { change = false; for (unsigned i = 1; i < binding.size(); ++i) { if (!binding.get(i)) continue; + // A misaligned higher-order binding would build an + // ill-sorted term. Abandon this refinement (no instance) + // rather than aborting the whole solve. + if (!euf::ho_matcher::subst_sorts_match(m, binding.get(i), binding, false)) + return; auto r = sub(binding.get(i), binding); change |= r != binding.get(i); binding[i] = r; @@ -700,6 +711,11 @@ namespace smt { for (expr* e : binding) { if (!e) return; // incomplete binding + // A leftover free (de Bruijn) variable means the binding is + // incomplete/misaligned; adding such a term would raise + // "Formulas should not contain unbound variables". Skip it. + if (!is_ground(e)) + return; if (!m_context->e_internalized(e)) { m_context->internalize(e, false); } @@ -718,6 +734,7 @@ namespace smt { vector> used_enodes; m_context->add_instance(q, nullptr, new_bindings.size(), new_bindings.data(), max_gen, st.m_min_top_generation, st.m_max_top_generation, used_enodes); + ++m_stat_ho_instances; } bool try_ho_refine(quantifier* qa, app* pat, unsigned num_bindings, enode* const* bindings, @@ -734,6 +751,7 @@ namespace smt { for (unsigned i = 0; i < num_bindings; ++i) s.push_back(bindings[i]->get_expr()); + unsigned num_instances = m_stat_ho_instances; m_ho_state.m_q = qa; m_ho_state.m_pat = pat; m_ho_state.m_num_bindings = num_bindings; @@ -748,11 +766,21 @@ namespace smt { verbose_stream() << " s[" << i << "] = " << mk_pp(s.get(i), m) << " sort=" << mk_pp(s.get(i)->get_sort(), m) << "\n";); m_ho_matcher->refine_ho_match(pat, s); + ++m_stat_ho_refine; return true; } bool model_based() const override { return m_fparams->m_mbqi; } + void collect_statistics(::statistics & st) const override { + if (m_fparams->m_ho_matching) { + st.update("ho-matching refinements", m_stat_ho_refine); + st.update("ho-matching instances", m_stat_ho_instances); + } + if (m_model_finder) + m_model_finder->collect_statistics(st); + } + bool mbqi_enabled(quantifier *q) const override { if (!m_fparams->m_mbqi_id) return true; const symbol &s = q->get_qid(); @@ -833,10 +861,7 @@ namespace smt { << " compiled=" << (p1 != mp) << " p1=" << mk_pp(p1, m) << "\n"); if (p1 != mp) { - if (!unary && j >= num_eager_multi_patterns) - m_lazy_mam->add_pattern(q1, p1); - else - m_mam->add_pattern(q1, p1); + m_lazy_mam->add_pattern(q1, p1); } } if (!unary) @@ -959,4 +984,4 @@ namespace smt { return alloc(default_qm_plugin); } -}; +} diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index 6d9a448222..d2c67a286b 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -186,5 +186,7 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, vector>& used_enodes) { return false; } + virtual void collect_statistics(::statistics & st) const {} + }; -}; +} diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 85f58cb2d0..34f6b3843f 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -404,5 +404,5 @@ namespace smt { return new_expr; } -}; +} diff --git a/src/smt/smt_quick_checker.h b/src/smt/smt_quick_checker.h index 8c8fd6c81f..b152ecd6d5 100644 --- a/src/smt/smt_quick_checker.h +++ b/src/smt/smt_quick_checker.h @@ -98,6 +98,6 @@ namespace smt { bool instantiate_not_sat(quantifier * q); bool instantiate_not_sat(quantifier * q, unsigned num_candidates, expr * const * candidates); }; -}; +} diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 720eac6c22..fcaf604558 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -141,6 +141,13 @@ namespace smt { typedef list relevancy_ehs; obj_map m_relevant_ehs; obj_map m_watches[2]; + // Over-approximating membership filter for m_watches: contains a superset + // of the expr ids that have (or ever had) a watch list for the given phase. + // It is monotonic (never cleared on erase/pop), so it can only yield false + // positives, never false negatives. This lets get_watches() skip the + // obj_map pointer-hash probe for the common unwatched-literal case at the + // assign_eh hotspot. + uint_set m_is_watched[2]; struct eh_trail { enum class kind { POS_WATCH, NEG_WATCH, HANDLER }; kind m_kind; @@ -185,17 +192,23 @@ namespace smt { } relevancy_ehs * get_watches(expr * n, bool val) { + unsigned idx = val ? 1 : 0; + if (!m_is_watched[idx].contains(n->get_id())) + return nullptr; relevancy_ehs * r = nullptr; - m_watches[val ? 1 : 0].find(n, r); - SASSERT(m_watches[val ? 1 : 0].contains(n) || r == 0); + m_watches[idx].find(n, r); + SASSERT(m_watches[idx].contains(n) || r == 0); return r; } void set_watches(expr * n, bool val, relevancy_ehs * ehs) { + unsigned idx = val ? 1 : 0; if (ehs == nullptr) - m_watches[val ? 1 : 0].erase(n); - else - m_watches[val ? 1 : 0].insert(n, ehs); + m_watches[idx].erase(n); + else { + m_watches[idx].insert(n, ehs); + m_is_watched[idx].insert(n->get_id()); + } } void push_trail(eh_trail const & t) { @@ -720,6 +733,6 @@ namespace smt { } relevancy_propagator * mk_relevancy_propagator(context & ctx) { return alloc(relevancy_propagator_imp, ctx); } -}; +} diff --git a/src/smt/smt_relevancy.h b/src/smt/smt_relevancy.h index 4827fffcb8..8bd7f7b95b 100644 --- a/src/smt/smt_relevancy.h +++ b/src/smt/smt_relevancy.h @@ -196,6 +196,6 @@ namespace smt { relevancy_propagator * mk_relevancy_propagator(context & ctx); -}; +} diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 69dec1348c..f13eed6fbc 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -941,6 +941,6 @@ namespace smt { setup_unknown(); } -}; +} diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index 897755ef71..ce00baf679 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -124,6 +124,6 @@ namespace smt { symbol const & get_logic() const { return m_logic; } void operator()(config_mode cm); }; -}; +} diff --git a/src/smt/smt_statistics.cpp b/src/smt/smt_statistics.cpp index 95acd48191..10c65401ac 100644 --- a/src/smt/smt_statistics.cpp +++ b/src/smt/smt_statistics.cpp @@ -25,5 +25,5 @@ namespace smt { memset(this, 0, sizeof(statistics)); } -}; +} diff --git a/src/smt/smt_statistics.h b/src/smt/smt_statistics.h index 11f7612e6f..831cf67b04 100644 --- a/src/smt/smt_statistics.h +++ b/src/smt/smt_statistics.h @@ -52,7 +52,7 @@ namespace smt { void reset(); }; -}; +} diff --git a/src/smt/smt_theory.cpp b/src/smt/smt_theory.cpp index be32edacb9..b762e757e5 100644 --- a/src/smt/smt_theory.cpp +++ b/src/smt/smt_theory.cpp @@ -261,5 +261,5 @@ namespace smt { return get_th_var(ctx.get_enode(e)); } -}; +} diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index 70b5556d68..79d8629e51 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -655,6 +655,6 @@ namespace smt { virtual bool is_fixed_propagated(theory_var v, expr_ref& val, literal_vector & explain) { return false; } }; -}; +} diff --git a/src/smt/smt_types.h b/src/smt/smt_types.h index 4b7fc4cc76..f8cff938f4 100644 --- a/src/smt/smt_types.h +++ b/src/smt/smt_types.h @@ -72,6 +72,6 @@ namespace smt { // if defined, then clauses have an extra mask field used to optimize backward subsumption, and backward/forward subsumption resolution. #define APPROX_LIT_SET -}; +} diff --git a/src/smt/smt_value_sort.h b/src/smt/smt_value_sort.h index 979afebf2d..e477a0b723 100644 --- a/src/smt/smt_value_sort.h +++ b/src/smt/smt_value_sort.h @@ -30,6 +30,6 @@ namespace smt { bool is_value_sort(ast_manager& m, expr* e); -}; +} diff --git a/src/smt/theory_arith.cpp b/src/smt/theory_arith.cpp index 6aee87408c..b97615c3e1 100644 --- a/src/smt/theory_arith.cpp +++ b/src/smt/theory_arith.cpp @@ -27,4 +27,4 @@ namespace smt { // template class theory_arith; template class smt::theory_arith; -}; +} diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index c5dc9df663..6b9a7dc75d 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1277,6 +1277,6 @@ namespace smt { // typedef theory_arith theory_smi_arith; -}; +} diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index c8fd25dbae..553e945967 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -147,7 +147,7 @@ namespace smt { result_map[it->m_var] = -1; } } - }; + } #ifdef Z3DEBUG /** @@ -2295,6 +2295,6 @@ namespace smt { } #endif -}; +} diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 6ba5eef741..2c352a6a25 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3570,5 +3570,5 @@ namespace smt { } -}; +} diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index b983475778..45dab16bfc 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -346,6 +346,6 @@ namespace smt { tout << enode_pp(_x, ctx) << " = " << enode_pp(_y, ctx) << "\n";); ctx.assign_eq(_x, _y, eq_justification(js)); } -}; +} diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index fe02fe8842..e1ea198e17 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1110,6 +1110,6 @@ namespace smt { return m_liberal_final_check || !m_changed_assignment ? FC_DONE : FC_CONTINUE; } -}; +} diff --git a/src/smt/theory_arith_inv.h b/src/smt/theory_arith_inv.h index f69d69d2f7..0b52ef7f17 100644 --- a/src/smt/theory_arith_inv.h +++ b/src/smt/theory_arith_inv.h @@ -229,6 +229,6 @@ namespace smt { #endif -}; +} diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 749ac82512..30cc8cbac2 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -2410,7 +2410,7 @@ final_check_status theory_arith::process_non_linear() { } -}; +} diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 81ed037623..be642f5b87 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -528,6 +528,6 @@ namespace smt { id++; } -}; +} diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index d35da46796..eadaf69c5d 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -505,4 +505,4 @@ namespace smt { st.update("array splits", m_stats.m_num_eq_splits); } -}; +} diff --git a/src/smt/theory_array.h b/src/smt/theory_array.h index 88f5678aea..135255ab78 100644 --- a/src/smt/theory_array.h +++ b/src/smt/theory_array.h @@ -114,5 +114,5 @@ namespace smt { ptr_vector const& parent_selects(enode* n) { return m_var_data[find(n->get_root()->get_th_var(get_id()))]->m_parent_selects; } }; -}; +} diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 19e89bd656..1d25d4893d 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -23,6 +23,7 @@ Revision History: #include "smt/smt_model_generator.h" #include "model/func_interp.h" #include "ast/ast_smt2_pp.h" +#include "ast/pattern/pattern_inference.h" namespace smt { @@ -413,6 +414,16 @@ namespace smt { expr * eq = m.mk_eq(sel1, sel2); expr_ref q(m.mk_forall(dimension, sorts.data(), names.data(), eq), m); ctx.get_rewriter()(q); + // The select terms are beta-reduced away by the rewriter, so the + // resulting quantifier carries no patterns. Infer patterns so that the + // e-matching engine can instantiate it (dynamically generated + // quantifiers bypass the pre-processing pattern inference pass). + if (is_forall(q) && to_quantifier(q)->get_num_patterns() == 0) { + pattern_inference_rw infer(m, ctx.get_fparams()); + expr_ref q2(m); + infer(q, q2); + q = q2; + } if (!ctx.b_internalized(q)) { ctx.internalize(q, true); } @@ -1053,4 +1064,4 @@ namespace smt { return result; } -}; +} diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index 629faec98c..34da46f93f 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -213,5 +213,5 @@ namespace smt { ~theory_array_base() override { restore_sorts(0); } }; -}; +} diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index e00f4cff93..86652d12ba 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -354,6 +354,14 @@ namespace smt { add_as_array(v1, n); for (enode* n : d2->m_lambdas) add_lambda(v1, n); + // When a lambda is equated to another array term, assert the congruence + // axiom n1 = n2 => forall k . select(n1, k) = select(n2, k). + // This lets positive equalities between lambdas (which have no select + // parents of their own) produce usable consequences. + enode* n1 = get_enode(v1); + enode* n2 = get_enode(v2); + if (is_lambda(n1->get_expr()) || is_lambda(n2->get_expr())) + assert_congruent(n1, n2); TRACE(array, tout << pp(get_enode(v1), m) << "\n"; tout << pp(get_enode(v2), m) << "\n"; @@ -845,6 +853,8 @@ namespace smt { } bool theory_array_full::has_non_beta_as_array() { + if (ctx.get_fparams().m_array_fake_support) + return false; for (enode* n : m_as_array) { for (enode* p : n->get_parents()) if (ctx.is_relevant(p) && !ctx.is_beta_redex(p, n)) { @@ -854,13 +864,28 @@ namespace smt { } for (enode* n : m_lambdas) for (enode* p : n->get_parents()) - if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n)) { + if (ctx.is_relevant(p) && !is_default(p) && !is_select(p) && !ctx.is_beta_redex(p, n) && !is_congruent_eq(p)) { TRACE(array, tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n"); return true; } return false; } + /** + \brief A relevant equality between two array terms whose roots coincide is + handled by the congruence axiom asserted on merge (see merge_eh / + assert_congruent). Such an equality parent does not make a lambda an + unsupported (non beta-redex) occurrence, so it should not trigger a + final-check give-up. + */ + bool theory_array_full::is_congruent_eq(enode* p) { + expr* a = nullptr, * b = nullptr; + if (!m.is_eq(p->get_expr(), a, b)) + return false; + return is_array_sort(p->get_arg(0)) && + p->get_arg(0)->get_root() == p->get_arg(1)->get_root(); + } + bool theory_array_full::instantiate_parent_stores_default(theory_var v) { SASSERT(v != null_theory_var); diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 9dae2dcb96..c9d2a41d70 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -92,6 +92,7 @@ namespace smt { enode_vector m_as_array; enode_vector m_lambdas; bool has_non_beta_as_array(); + bool is_congruent_eq(enode* p); bool instantiate_select_const_axiom(enode* select, enode* cnst); bool instantiate_select_as_array_axiom(enode* select, enode* arr); @@ -118,5 +119,5 @@ namespace smt { void propagate() override; }; -}; +} diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index b535838438..f09be95069 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -2071,4 +2071,4 @@ namespace smt { #endif -}; +} diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index 247424e18c..6d64b7a14d 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -296,4 +296,4 @@ namespace smt { bool check_invariant(); bool check_zero_one_bits(theory_var v); }; -}; +} diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 3782f54d12..6d58f0c2f4 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -1414,4 +1414,4 @@ namespace smt { } -}; +} diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index be6b3d61ab..d76740aed9 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -215,6 +215,6 @@ namespace smt { bool include_func_interp(func_decl* f) override; }; -}; +} diff --git a/src/smt/theory_dense_diff_logic.cpp b/src/smt/theory_dense_diff_logic.cpp index 3d352ee845..7057a47f24 100644 --- a/src/smt/theory_dense_diff_logic.cpp +++ b/src/smt/theory_dense_diff_logic.cpp @@ -23,4 +23,4 @@ namespace smt { template class theory_dense_diff_logic; template class theory_dense_diff_logic; template class theory_dense_diff_logic; -}; +} diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 8c2d62aa9a..d60d9edaff 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -292,6 +292,6 @@ namespace smt { typedef theory_dense_diff_logic theory_dense_i; typedef theory_dense_diff_logic theory_dense_smi; typedef theory_dense_diff_logic theory_dense_si; -}; +} diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 243629db79..eba0e0ab83 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -1123,6 +1123,6 @@ namespace smt { return f; } -}; +} diff --git a/src/smt/theory_diff_logic.cpp b/src/smt/theory_diff_logic.cpp index 1664dbfe2f..96593cdc00 100644 --- a/src/smt/theory_diff_logic.cpp +++ b/src/smt/theory_diff_logic.cpp @@ -31,9 +31,9 @@ template class theory_diff_logic; template class theory_diff_logic; -}; +} namespace simplex { template class simplex; template class sparse_matrix; -}; +} diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index ac73ca820f..3781042ef5 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -407,7 +407,7 @@ namespace smt { typedef theory_diff_logic theory_fidl; typedef theory_diff_logic theory_rdl; typedef theory_diff_logic theory_frdl; -}; +} diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index a3cd84853a..2783d7def4 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -291,4 +291,4 @@ namespace smt { theory* mk_theory_dl(context& ctx) { return alloc(theory_dl, ctx); } -}; +} diff --git a/src/smt/theory_dl.h b/src/smt/theory_dl.h index 4bcd94e83f..fb87c9f302 100644 --- a/src/smt/theory_dl.h +++ b/src/smt/theory_dl.h @@ -23,6 +23,6 @@ namespace smt { theory* mk_theory_dl(context& ctx); -}; +} diff --git a/src/smt/theory_dummy.cpp b/src/smt/theory_dummy.cpp index 7f8af5a9d0..58bdeaab6c 100644 --- a/src/smt/theory_dummy.cpp +++ b/src/smt/theory_dummy.cpp @@ -70,4 +70,4 @@ namespace smt { return m_name; } -}; +} diff --git a/src/smt/theory_dummy.h b/src/smt/theory_dummy.h index de77f292d6..bf4ace8db5 100644 --- a/src/smt/theory_dummy.h +++ b/src/smt/theory_dummy.h @@ -51,6 +51,6 @@ namespace smt { char const * get_name() const override; }; -}; +} diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 492595f609..b9fb4bf69d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -721,4 +721,4 @@ namespace smt { out << r->get_id() << " --> " << enode_pp(n, ctx) << "\n"; } } -}; +} diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 14797f62a4..50493a30c6 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -126,5 +126,5 @@ namespace smt { app* get_ite_value(expr* e); }; -}; +} diff --git a/src/smt/theory_opt.cpp b/src/smt/theory_opt.cpp index 365315bf2e..f1917a3a86 100644 --- a/src/smt/theory_opt.cpp +++ b/src/smt/theory_opt.cpp @@ -74,4 +74,4 @@ namespace smt { return a.is_numeral(term); } -}; +} diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 73c9d5cba5..5fdcfbdcc3 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -424,4 +424,4 @@ namespace smt { void propagate() override; static literal assert_ge(context& ctx, unsigned k, unsigned n, literal const* xs); }; -}; +} diff --git a/src/smt/theory_polymorphism.h b/src/smt/theory_polymorphism.h index 8fd88c69b3..95e0afc136 100644 --- a/src/smt/theory_polymorphism.h +++ b/src/smt/theory_polymorphism.h @@ -67,8 +67,18 @@ namespace smt { } final_check_status final_check_eh(unsigned) override { - if (m_inst.pending()) + if (m_inst.pending()) { + // There are still polymorphic axioms to instantiate. Force the + // solver to fail under the theory assumption so that a new + // research round (see should_research) can assert the new + // instances. Assigning the negation of the (already true) + // assumption creates a conflict, so we must return FC_CONTINUE + // to let conflict resolution turn it into l_false; returning + // FC_DONE here would report l_true while the context is + // inconsistent, violating a core search invariant. ctx.assign(~mk_literal(m_assumption), nullptr); + return FC_CONTINUE; + } return FC_DONE; } @@ -96,10 +106,18 @@ namespace smt { theory(ctx, poly_family_id), m_inst(ctx.get_manager(), m_trail), m_assumption(ctx.get_manager()) {} + + ~theory_polymorphism() override { + // Undo level-0 trail items (e.g. the inc_ref balancing entries that + // m_inst pushes for m_from_instantiation). trail_stack's destructor + // does not call reset(), so without this the references those items + // hold would leak when the theory is destroyed. + m_trail.reset(); + } void init_model(model_generator & mg) override { } }; -}; +} diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index ee2ae002ae..50a267d653 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -642,6 +642,6 @@ namespace smt { expr* expr2rep(expr* e) override; bool get_length(expr* e, rational& r) override; }; -}; +} diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index 9571f46b76..26ad3573d8 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -43,6 +43,6 @@ namespace smt { }; -}; +} diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index 439ffdb7ea..6f382dca07 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -167,4 +167,4 @@ namespace smt { void propagate() override; void display(std::ostream& out) const override {} }; -}; +} diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index e94df49ebc..eeb19da847 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -358,7 +358,7 @@ namespace smt { typedef theory_utvpi theory_rutvpi; typedef theory_utvpi theory_iutvpi; -}; +} diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 9d011299dc..6c96bb92fa 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -965,6 +965,6 @@ namespace smt { } -}; +} diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index d3b190010f..53b5c0b5fa 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -362,4 +362,4 @@ namespace smt { m_normalize = false; } -}; +} diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 65461eb708..42cfbb3fd6 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -134,5 +134,5 @@ namespace smt { }; -}; +} diff --git a/src/smt/watch_list.cpp b/src/smt/watch_list.cpp index 973e586faa..08c8f117b5 100644 --- a/src/smt/watch_list.cpp +++ b/src/smt/watch_list.cpp @@ -128,4 +128,4 @@ namespace smt { begin_lits_core() += sizeof(literal); } -}; +} diff --git a/src/smt/watch_list.h b/src/smt/watch_list.h index e974ea51c3..f866adf094 100644 --- a/src/smt/watch_list.h +++ b/src/smt/watch_list.h @@ -193,6 +193,6 @@ namespace smt { }; -}; +} diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 32b8bb9b65..6abf5dbb96 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -496,6 +496,7 @@ void asserted_formulas::simplify_fmls::operator()() { expr_ref result(m); proof_ref result_pr(m); simplify(j, result, result_pr); + SASSERT(is_well_sorted(m, j.fml())); if (m.proofs_enabled()) { if (!result_pr) result_pr = m.mk_rewrite(j.fml(), result); result_pr = m.mk_modus_ponens(j.pr(), result_pr); diff --git a/src/solver/assertions/asserted_formulas.h b/src/solver/assertions/asserted_formulas.h index ba0b1f8406..14f9c93968 100644 --- a/src/solver/assertions/asserted_formulas.h +++ b/src/solver/assertions/asserted_formulas.h @@ -190,7 +190,7 @@ class asserted_formulas { } \ void post_op() override { if (REDUCE) af.reduce_and_solve(); } \ bool should_apply() const override { return APP; } \ - }; + } #define MK_SIMPLIFIERF(NAME, FUNCTOR, MSG, APP, REDUCE) MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, (af.m), REDUCE) diff --git a/src/solver/check_logic.cpp b/src/solver/check_logic.cpp index bc92c8a30a..e81167f677 100644 --- a/src/solver/check_logic.cpp +++ b/src/solver/check_logic.cpp @@ -469,7 +469,7 @@ struct check_logic::imp { else if (m.is_builtin_family_id(fid)) { // nothing to check } - else if (fid == m_seq_util.get_family_id()) { + else if (fid == m_seq_util.get_family_id() || m_seq_util.is_char(s)) { // nothing to check } else if (fid == m_dt_util.get_family_id() && m_dt) { diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 4835eacd9c..e5c20462de 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -26,7 +26,7 @@ struct bv_bound_chk_stats { unsigned m_unsats; unsigned m_singletons; unsigned m_reduces; - bv_bound_chk_stats() : m_unsats(0), m_singletons(0), m_reduces(0) {}; + bv_bound_chk_stats() : m_unsats(0), m_singletons(0), m_reduces(0) {} }; struct bv_bound_chk_rewriter_cfg : public default_rewriter_cfg { diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index 213f01f623..476e97eb1d 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -57,7 +57,7 @@ public: virtual simplifier * translate(ast_manager & m) = 0; virtual unsigned scope_level() const = 0; virtual void updt_params(params_ref const & p) {} - void set_occs(goal_num_occurs& occs) { m_occs = &occs; }; + void set_occs(goal_num_occurs& occs) { m_occs = &occs; } bool shared(expr* t) const; }; diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 6807cdaa1e..7aecd4d505 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -27,6 +27,7 @@ Notes: #include "ast/datatype_decl_plugin.h" #include "ast/seq_decl_plugin.h" #include "ast/for_each_expr.h" +#include "ast/polymorphism_util.h" #include "tactic/core/collect_occs.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" @@ -936,6 +937,21 @@ class elim_uncnstr_tactic : public tactic { m_rw = alloc(rw, m(), produce_proofs, m_vars, m_nonvars, m_disabled, m_mc.get(), m_max_memory, m_max_steps); } + // The manager-wide has_type_vars() flag is a coarse over-approximation: it becomes + // true as soon as any type variable is created, including the type variables used to + // define the polymorphic signatures of builtin plugins (e.g. finite_set). Those never + // occur in the actual goal, so relying on the global flag needlessly disables this + // tactic. Check whether the goal itself contains type-variable typed terms instead. + bool goal_has_type_vars(goal_ref const & g) { + if (!m().has_type_vars()) + return false; + polymorphism::util u(m()); + for (unsigned i = 0; i < g->size(); ++i) + if (u.has_type_vars(g->form(i))) + return true; + return false; + } + void run(goal_ref const & g, goal_ref_buffer & result) { bool produce_proofs = g->proofs_enabled(); TRACE(goal, g->display(tout);); @@ -945,7 +961,7 @@ class elim_uncnstr_tactic : public tactic { collect_occs p; p(*g, m_vars); disable_quantified(g); - if (m_vars.empty() || recfun::util(m()).has_rec_defs()) { + if (m_vars.empty() || recfun::util(m()).has_rec_defs() || goal_has_type_vars(g)) { result.push_back(g.get()); // did not increase depth since it didn't do anything. return; diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index c05116c0a1..194388bde8 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -341,7 +341,7 @@ private: } typedef hashtable uint_set; - typedef obj_map app_siblings;; + typedef obj_map app_siblings; class siblings { app_map const& m_colors; diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 22e0f498be..d91ae3192a 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -1012,7 +1012,7 @@ public: result.reset(); // assumes in is not strenthened to one of the branches throw tactic_exception("failed-if-branching tactical"); } - }; + } tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); diff --git a/src/test/ho_matcher.cpp b/src/test/ho_matcher.cpp index dccd8af082..a6dee5891b 100644 --- a/src/test/ho_matcher.cpp +++ b/src/test/ho_matcher.cpp @@ -170,6 +170,147 @@ namespace euf { m_matcher.add_pattern(pat.get()); m_matcher(pat, t, 3, 1); } + + // Structural regression test derived from TPTP ANA067^1 (which fails + // under smt.ho_matching=true inside the full solver). + // pattern: (select (select v0 v3) v2) with v0 a doubly-nested array (flex head) + // term: (select K ...) matched term is itself array-sorted. + // Exercises imitation/projection of a flex head against an array-sorted + // term. The matcher must build only well-sorted bindings; the debug + // asserts in match_goals::push and mk_project catch any regression that + // commits an ill-sorted (extra array level) lambda/select. + void test7() { + sort_ref r(m_arith.mk_real(), m); + sort_ref arr_rb(m_array.mk_array_sort(r, m.mk_bool_sort()), m); // (Array Real Bool) + sort_ref arr_r_rb(m_array.mk_array_sort(r, arr_rb), m); // (Array Real (Array Real Bool)) + sort_ref arr_r_r_rb(m_array.mk_array_sort(r, arr_r_rb), m); // v0 sort + + expr_ref v0(m.mk_var(0, arr_r_r_rb), m); + expr_ref v2(m.mk_var(2, r), m); + expr_ref v3(m.mk_var(3, r), m); + expr_ref pat(m_array.mk_select(v0, v3), m); + pat = m_array.mk_select(pat, v2); + + expr_ref K(m.mk_const(symbol("K"), arr_r_rb), m); + expr_ref b(m.mk_const(symbol("b"), r), m); + expr_ref t(m_array.mk_select(K, b), m); + + IF_VERBOSE(0, verbose_stream() << "test7: " << pat << " =?= " << t << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t, 5); + + // Faithful variant: the term index argument is itself + // (select fun (lambda (t) c)) as in ANA067^1, i.e. a term whose + // subterm is a function(array)-valued lambda. This forces the + // matcher to decompose/imitate against a lambda-bearing term. + sort_ref arr_rr(m_array.mk_array_sort(r, r), m); // (Array Real Real) + sort_ref fun_sort(m_array.mk_array_sort(arr_rr, r), m); // (Array (Array Real Real) Real) + symbol tt("t"); + sort* r_s = r.get(); + expr_ref c0(m.mk_const(symbol("c0"), r), m); + expr_ref lam(m.mk_lambda(1, &r_s, &tt, c0), m); // (lambda (t Real) c0) + expr_ref fun(m.mk_const(symbol("fun"), fun_sort), m); + expr_ref idx(m_array.mk_select(fun, lam), m); // : Real + expr_ref t2(m_array.mk_select(K, idx), m); + IF_VERBOSE(0, verbose_stream() << "test7b: " << pat << " =?= " << t2 << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t2, 5); + } + + // Structural regression test derived from TPTP PHI008^4 (which fails + // under smt.ho_matching=true inside the full solver). + // pattern: (select v3 v4) v3 flex head, v4 a flex arg of an array sort + // term: (select P ...) P a concrete array constant. + // Exercises projecting/imitating a flex head over a function(array)-sorted + // argument (incl. a lambda-valued term arg). The matcher must build only + // well-sorted bindings; debug asserts guard against regressions. + void test8() { + sort_ref i(m.mk_uninterpreted_sort(symbol("qML_i")), m); + sort_ref mu(m.mk_uninterpreted_sort(symbol("qML_mu")), m); + sort_ref arr_ib(m_array.mk_array_sort(i, m.mk_bool_sort()), m); // (Array qML_i Bool) + sort_ref arr_mu_ib(m_array.mk_array_sort(mu, arr_ib), m); // (Array qML_mu (Array qML_i Bool)) + sort_ref p_sort(m_array.mk_array_sort(arr_mu_ib, arr_ib), m); // P sort + + expr_ref v3(m.mk_var(3, p_sort), m); + expr_ref v4(m.mk_var(4, arr_mu_ib), m); + expr_ref pat(m_array.mk_select(v3, v4), m); + + expr_ref P(m.mk_const(symbol("P"), p_sort), m); + expr_ref ell(m.mk_const(symbol("ell"), arr_mu_ib), m); + expr_ref t(m_array.mk_select(P, ell), m); + + IF_VERBOSE(0, verbose_stream() << "test8: " << pat << " =?= " << t << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t, 9); + + // Variant with a lambda-valued term argument, mirroring PHI008's + // (select scott_P (lambda (Y) (lambda (Z) ...))) goal that forces + // the matcher to decompose a flex head against a lambda term. + symbol yv("Y"); + sort* mu_s = mu.get(); + expr_ref cbody(m.mk_const(symbol("C"), arr_ib), m); + expr_ref lam(m.mk_lambda(1, &mu_s, &yv, cbody), m); // (lambda (Y qML_mu) C) : arr_mu_ib + expr_ref t2(m_array.mk_select(P, lam), m); + IF_VERBOSE(0, verbose_stream() << "test8b: " << pat << " =?= " << t2 << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, t2, 9); + } + + // Structural regression test for the ITP127-style shape (fails under + // smt.ho_matching=true inside the full solver). The flex head H has an + // applied result sort that is *itself* an array (monomo = (Array d Bool)). + // Matching (select (select H x1) x2) =?= f where f is array-sorted is a + // case where imitation could build a lambda with an extra array level + // (an ill-sorted select). The matcher must build only well-sorted + // bindings; debug asserts guard against regressions. + void test9() { + sort_ref c(m.mk_uninterpreted_sort(symbol("c")), m); + sort_ref d(m.mk_uninterpreted_sort(symbol("d")), m); + sort_ref monomo(m_array.mk_array_sort(d, m.mk_bool_sort()), m); // (Array d Bool) + sort_ref h1(m_array.mk_array_sort(c, monomo), m); // (Array c monomo) + sort_ref h2(m_array.mk_array_sort(c, h1), m); // (Array c (Array c monomo)) + + expr_ref H(m.mk_var(0, h2), m); + expr_ref x1(m.mk_var(1, c), m); + expr_ref x2(m.mk_var(2, c), m); + expr_ref pat(m_array.mk_select(H, x1), m); + pat = m_array.mk_select(pat, x2); // (select (select H x1) x2) : monomo + + expr_ref f(m.mk_const(symbol("f"), monomo), m); // f : (Array d Bool) + IF_VERBOSE(0, verbose_stream() << "test9: " << pat << " =?= " << f << "\n";); + m_matcher.add_pattern(pat.get()); + m_matcher(pat, f, 3); + } + + // Faithful isolation test for the refine-time sort guard used by + // ho_matcher::refine_ho_match (throws "sort mismatch ..." on failure). + // Mirrors the SEV510^1 family where a bound-variable binding's sort + // disagrees with the pattern variable it would fill. subst_sorts_match + // must detect the mismatch (return false) and accept the matching case. + void test10() { + sort_ref int2int(m_array.mk_array_sort(m_int, m_int), m); + // pattern (select v0 v1): v0 is the array (idx 0), v1 the index (idx 1) + expr_ref v0(m.mk_var(0, int2int), m); + expr_ref v1(m.mk_var(1, m_int), m); + expr_ref pat(m_array.mk_select(v0, v1), m); + + // std_order=true: var idx maps to s[size-idx-1], so idx0->s[1], idx1->s[0]. + expr_ref arr(m.mk_const(symbol("arr"), int2int), m); + expr_ref i0(m_arith.mk_int(0), m); + + // Well-sorted substitution: idx0 -> arr (array), idx1 -> 0 (int). + expr_ref_vector s_ok(m); + s_ok.push_back(i0); // s[0] -> var idx 1 (Int) OK + s_ok.push_back(arr); // s[1] -> var idx 0 (Array) OK + VERIFY(ho_matcher::subst_sorts_match(m, pat, s_ok, true)); + + // Ill-sorted substitution: idx0 (array var) bound to an Int -> mismatch. + expr_ref_vector s_bad(m); + s_bad.push_back(i0); // s[0] -> var idx 1 (Int) OK + s_bad.push_back(i0); // s[1] -> var idx 0 expects Array, got Int -> mismatch + VERIFY(!ho_matcher::subst_sorts_match(m, pat, s_bad, true)); + IF_VERBOSE(0, verbose_stream() << "test10: subst_sorts_match detects sort mismatch\n";); + } }; } @@ -183,6 +324,10 @@ void tst_ho_matcher() { tm.test4(); tm.test5(); tm.test6(); + tm.test7(); + tm.test8(); + tm.test9(); + tm.test10(); } catch (std::exception const& ex) { std::cout << ex.what() << "\n"; diff --git a/src/test/seq_rewriter.cpp b/src/test/seq_rewriter.cpp index 658675fa72..920a4ae4ac 100644 --- a/src/test/seq_rewriter.cpp +++ b/src/test/seq_rewriter.cpp @@ -10,12 +10,19 @@ Tests: 4. Range ∪ Range → merged range for overlapping/adjacent 5. Complement of range → one or two ranges 6. Downstream operators absorb empty ranges correctly + 15. Symbolic-bound range membership rewrite (structural) + 16. Symbolic-bound range membership: concrete element, symbolic bounds (structural) + 17. Solver: (str.in_re x (re.range x x)) sat when len(x)=1 + 18. Solver: (str.in_re x (re.range x x)) unsat when len(x)=2 + 19. Solver: inverted symbolic bounds make membership unsatisfiable --*/ +#include "ast/arith_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/reg_decl_plugins.h" #include "ast/rewriter/th_rewriter.h" #include "ast/seq_decl_plugin.h" +#include "smt/smt_context.h" #include // Build a single-char string literal expression. @@ -167,5 +174,86 @@ void tst_seq_rewriter() { ENSURE(su.re.is_empty(e)); } + // ----------------------------------------------------------------------- + // 15. Symbolic-bound range membership rewrite (structural). + // (str.in_re x (re.range x x)) with symbolic x should be unfolded + // by the rewriter into a conjunction of length and ordering + // constraints, not left stuck as an uninterpreted membership term. + // ----------------------------------------------------------------------- + { + app_ref x(m.mk_fresh_const("x", str_sort), m); + expr_ref rng(su.re.mk_range(x, x), m); + expr_ref e(su.re.mk_in_re(x, rng), m); + rw(e); + std::cout << "symbolic range (x in [x,x]): " << mk_pp(e, m) << "\n"; + ENSURE(m.is_and(e)); + } + + // ----------------------------------------------------------------------- + // 16. Symbolic-bound range membership: concrete element, symbolic bounds. + // (str.in_re "b" (re.range lo hi)) should also be unfolded to a + // conjunction when lo/hi are free variables. + // ----------------------------------------------------------------------- + { + app_ref lo(m.mk_fresh_const("lo", str_sort), m); + app_ref hi(m.mk_fresh_const("hi", str_sort), m); + expr_ref b_str(su.str.mk_string(zstring('b')), m); + expr_ref rng(su.re.mk_range(lo, hi), m); + expr_ref e(su.re.mk_in_re(b_str, rng), m); + rw(e); + std::cout << "symbolic range (\"b\" in [lo,hi]): " << mk_pp(e, m) << "\n"; + ENSURE(m.is_and(e)); + } + + // ----------------------------------------------------------------------- + // Solver-level tests: the unfolded conjunction must be decidable. + // ----------------------------------------------------------------------- + { + arith_util a_util(m); + + // 17. sat: (str.in_re x (re.range x x)) ∧ len(x)=1 + { + smt_params sp; + smt::context ctx(m, sp); + app_ref x(m.mk_fresh_const("x", str_sort), m); + ctx.assert_expr(su.re.mk_in_re(x, su.re.mk_range(x, x))); + ctx.assert_expr(m.mk_eq(su.str.mk_length(x), a_util.mk_int(1))); + lbool res = ctx.check(); + std::cout << "symbolic range solver sat (len=1): " << res << "\n"; + ENSURE(res == l_true); + } + + // 18. unsat: (str.in_re x (re.range x x)) ∧ len(x)=2 + // The unfolded membership requires len(x)=1, which contradicts len(x)=2. + { + smt_params sp; + smt::context ctx(m, sp); + app_ref x(m.mk_fresh_const("x", str_sort), m); + ctx.assert_expr(su.re.mk_in_re(x, su.re.mk_range(x, x))); + ctx.assert_expr(m.mk_eq(su.str.mk_length(x), a_util.mk_int(2))); + lbool res = ctx.check(); + std::cout << "symbolic range solver unsat (len=2): " << res << "\n"; + ENSURE(res == l_false); + } + + // 19. unsat: inverted symbolic bounds make membership false. + // (str.in_re "b" (re.range lo hi)) ∧ lo="z" ∧ hi="a" + // The unfolded conjunction requires lo <=_lex "b" <=_lex hi, but + // "z" > "b" > "a" so the ordering constraints are unsatisfiable. + { + smt_params sp; + smt::context ctx(m, sp); + app_ref lo(m.mk_fresh_const("lo", str_sort), m); + app_ref hi(m.mk_fresh_const("hi", str_sort), m); + expr_ref b_str(su.str.mk_string(zstring('b')), m); + ctx.assert_expr(su.re.mk_in_re(b_str, su.re.mk_range(lo, hi))); + ctx.assert_expr(m.mk_eq(lo, su.str.mk_string(zstring('z')))); + ctx.assert_expr(m.mk_eq(hi, su.str.mk_string(zstring('a')))); + lbool res = ctx.check(); + std::cout << "symbolic range solver inverted bounds unsat: " << res << "\n"; + ENSURE(res == l_false); + } + } + std::cout << "tst_seq_rewriter: all tests passed\n"; } diff --git a/src/util/sat_literal.h b/src/util/sat_literal.h index fb22ce5e17..95209fef24 100644 --- a/src/util/sat_literal.h +++ b/src/util/sat_literal.h @@ -190,7 +190,7 @@ namespace sat { return out << mk_lits_pp(ls.size(), ls.data()); } -}; +} namespace std { @@ -198,4 +198,4 @@ namespace std { if (l.sign()) return "-" + to_string(l.var()); return to_string(l.var()); } -}; +} diff --git a/src/util/sat_sls.h b/src/util/sat_sls.h index 82b84bd03d..3289d8a29e 100644 --- a/src/util/sat_sls.h +++ b/src/util/sat_sls.h @@ -36,6 +36,6 @@ namespace sat { inline std::ostream& operator<<(std::ostream& out, clause_info const& ci) { return out << ci.m_clause << " w: " << ci.m_weight << " nt: " << ci.m_num_trues; } -}; +} diff --git a/src/util/sign.h b/src/util/sign.h index 5221b3f684..8c21716495 100644 --- a/src/util/sign.h +++ b/src/util/sign.h @@ -18,7 +18,7 @@ Author: #pragma once typedef enum { sign_neg = -1, sign_zero = 0, sign_pos = 1} sign; -static inline sign operator-(sign s) { switch (s) { case sign_neg: return sign_pos; case sign_pos: return sign_neg; default: return sign_zero; } }; +static inline sign operator-(sign s) { switch (s) { case sign_neg: return sign_pos; case sign_pos: return sign_neg; default: return sign_zero; } } static inline sign to_sign(int s) { return s == 0 ? sign_zero : (s > 0 ? sign_pos : sign_neg); } static inline sign operator*(sign a, sign b) { return to_sign((int)a * (int)b); } static inline bool is_zero(sign s) { return s == sign_zero; } diff --git a/src/util/util.h b/src/util/util.h index d580209e94..34eec199bd 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -270,7 +270,7 @@ public: scoped_ptr& operator=(scoped_ptr&& other) noexcept { *this = other.detach(); return *this; - }; + } T * detach() { T* tmp = m_ptr;