mirror of
https://github.com/Z3Prover/z3
synced 2026-06-21 08:00:27 +00:00
Merge branch 'master' into c3
This commit is contained in:
commit
043c6c0ad1
259 changed files with 18907 additions and 3725 deletions
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
|
|
@ -1,6 +1,8 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- directory: /
|
||||
ignore:
|
||||
- dependency-name: "github/gh-aw-actions/**" # Managed by gh aw compile. Version-locked to the gh-aw compiler; do not bump.
|
||||
package-ecosystem: github-actions
|
||||
schedule:
|
||||
interval: weekly
|
||||
version: 2
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ safe-outputs:
|
|||
title-prefix: "[Research Trends] "
|
||||
category: "Agentic Workflows"
|
||||
close-older-discussions: true
|
||||
expires: 60
|
||||
expires: 60d
|
||||
missing-tool:
|
||||
create-issue: true
|
||||
noop:
|
||||
|
|
@ -295,4 +295,4 @@ Store for next run:
|
|||
- DO NOT reproduce copyrighted paper text beyond short fair-use quotes.
|
||||
- DO close older Research Trends discussions automatically (configured).
|
||||
- DO always cite sources (arXiv ID, DOI, GitHub URL) so maintainers can verify.
|
||||
- DO use cache memory to track longitudinal trends across months.
|
||||
- DO use cache memory to track longitudinal trends across months.
|
||||
2
.github/workflows/android-build.yml
vendored
2
.github/workflows/android-build.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
tar -cvf z3-build-${{ matrix.android-abi }}.tar *.jar *.so
|
||||
|
||||
- name: Archive production artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: android-build-${{ matrix.android-abi }}
|
||||
path: build/z3-build-${{ matrix.android-abi }}.tar
|
||||
|
|
|
|||
2
.github/workflows/api-coherence-checker.md
vendored
2
.github/workflows/api-coherence-checker.md
vendored
|
|
@ -13,12 +13,10 @@ network: defaults
|
|||
|
||||
tools:
|
||||
cache-memory: true
|
||||
serena: ["java", "python", "typescript", "csharp"]
|
||||
github:
|
||||
toolsets: [default]
|
||||
bash: [":*"]
|
||||
edit: {}
|
||||
glob: {}
|
||||
web-search: {}
|
||||
|
||||
safe-outputs:
|
||||
|
|
|
|||
2
.github/workflows/build-warning-fixer.md
vendored
2
.github/workflows/build-warning-fixer.md
vendored
|
|
@ -5,8 +5,6 @@ on:
|
|||
workflow_dispatch:
|
||||
permissions: read-all
|
||||
tools:
|
||||
view: {}
|
||||
glob: {}
|
||||
edit:
|
||||
bash: true
|
||||
safe-outputs:
|
||||
|
|
|
|||
2
.github/workflows/build-z3-cache.yml
vendored
2
.github/workflows/build-z3-cache.yml
vendored
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
|
||||
- name: Restore or create cache
|
||||
id: cache-z3
|
||||
uses: actions/cache@v5.0.4
|
||||
uses: actions/cache@v5.0.5
|
||||
with:
|
||||
path: |
|
||||
build/z3
|
||||
|
|
|
|||
22
.github/workflows/ci.yml
vendored
22
.github/workflows/ci.yml
vendored
|
|
@ -83,8 +83,16 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python virtual environment
|
||||
run: "/opt/python/cp38-cp38/bin/python -m venv $PWD/env"
|
||||
run: "$PYTHON -m venv $PWD/env"
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
|
|
@ -123,8 +131,16 @@ jobs:
|
|||
mkdir -p /tmp/arm-toolchain/
|
||||
tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python virtual environment
|
||||
run: "/opt/python/cp38-cp38/bin/python -m venv $PWD/env"
|
||||
run: "$PYTHON -m venv $PWD/env"
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
|
|
@ -315,7 +331,7 @@ jobs:
|
|||
|
||||
- name: Setup Julia (if needed)
|
||||
if: matrix.name == 'debugClang'
|
||||
uses: julia-actions/setup-julia@v2
|
||||
uses: julia-actions/setup-julia@v3
|
||||
with:
|
||||
version: '1'
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ tools:
|
|||
cache-memory: true
|
||||
github:
|
||||
toolsets: [default]
|
||||
view: {}
|
||||
glob: {}
|
||||
edit: {}
|
||||
bash:
|
||||
- "clang-format --version"
|
||||
|
|
|
|||
1393
.github/workflows/code-simplifier.lock.yml
generated
vendored
1393
.github/workflows/code-simplifier.lock.yml
generated
vendored
File diff suppressed because it is too large
Load diff
819
.github/workflows/code-simplifier.md
vendored
819
.github/workflows/code-simplifier.md
vendored
|
|
@ -1,434 +1,3 @@
|
|||
<<<<<<< current (local changes)
|
||||
---
|
||||
on:
|
||||
schedule: daily
|
||||
skip-if-match: is:pr is:open in:title "[code-simplifier]"
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
safe-outputs:
|
||||
create-issue:
|
||||
labels:
|
||||
- refactoring
|
||||
- code-quality
|
||||
- automation
|
||||
title-prefix: "[code-simplifier] "
|
||||
noop:
|
||||
report-as-issue: false
|
||||
description: Analyzes recently modified code and creates pull requests with simplifications that improve clarity, consistency, and maintainability while preserving functionality
|
||||
name: Code Simplifier
|
||||
source: github/gh-aw/.github/workflows/code-simplifier.md@76d37d925abd44fee97379206f105b74b91a285b
|
||||
strict: true
|
||||
timeout-minutes: 30
|
||||
tools:
|
||||
github:
|
||||
toolsets:
|
||||
- default
|
||||
tracker-id: code-simplifier
|
||||
---
|
||||
<!-- This prompt will be imported in the agentic workflow .github/workflows/code-simplifier.md at runtime. -->
|
||||
<!-- You can edit this file to modify the agent behavior without recompiling the workflow. -->
|
||||
|
||||
# Code Simplifier Agent
|
||||
|
||||
You are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality. Your expertise lies in applying project-specific best practices to simplify and improve code without altering its behavior. You prioritize readable, explicit code over overly compact solutions. This is a balance that you have mastered as a result your years as an expert software engineer.
|
||||
|
||||
## Your Mission
|
||||
|
||||
Analyze recently modified code from the last 24 hours and apply refinements that improve code quality while preserving all functionality. Create a GitHub issue with a properly formatted diff if improvements are found.
|
||||
|
||||
## Current Context
|
||||
|
||||
- **Repository**: ${{ github.repository }}
|
||||
- **Workspace**: ${{ github.workspace }}
|
||||
|
||||
## Phase 1: Identify Recently Modified Code
|
||||
|
||||
### 1.1 Find Recent Changes
|
||||
|
||||
Search for merged pull requests and commits from the last 24 hours:
|
||||
|
||||
```bash
|
||||
# Get yesterday's date in ISO format
|
||||
YESTERDAY=$(date -d '1 day ago' '+%Y-%m-%d' 2>/dev/null || date -v-1d '+%Y-%m-%d')
|
||||
|
||||
# List recent commits
|
||||
git log --since="24 hours ago" --pretty=format:"%H %s" --no-merges
|
||||
```
|
||||
|
||||
Use GitHub tools to:
|
||||
- Search for pull requests merged in the last 24 hours: `repo:${{ github.repository }} is:pr is:merged merged:>=${YESTERDAY}`
|
||||
- Get details of merged PRs to understand what files were changed
|
||||
- List commits from the last 24 hours to identify modified files
|
||||
|
||||
### 1.2 Extract Changed Files
|
||||
|
||||
For each merged PR or recent commit:
|
||||
- Use `pull_request_read` with `method: get_files` to list changed files
|
||||
- Use `get_commit` to see file changes in recent commits
|
||||
- Focus on source code files (`.go`, `.js`, `.ts`, `.tsx`, `.cjs`, `.py`, etc.)
|
||||
- Exclude test files, lock files, and generated files
|
||||
|
||||
### 1.3 Determine Scope
|
||||
|
||||
If **no files were changed in the last 24 hours**, exit gracefully without creating a PR:
|
||||
|
||||
```
|
||||
✅ No code changes detected in the last 24 hours.
|
||||
Code simplifier has nothing to process today.
|
||||
```
|
||||
|
||||
If **files were changed**, proceed to Phase 2.
|
||||
|
||||
## Phase 2: Analyze and Simplify Code
|
||||
|
||||
### 2.1 Review Project Standards
|
||||
|
||||
Before simplifying, review the project's coding standards from relevant documentation:
|
||||
|
||||
- For Go projects: Check `AGENTS.md`, `DEVGUIDE.md`, or similar files
|
||||
- For JavaScript/TypeScript: Look for `CLAUDE.md`, style guides, or coding conventions
|
||||
- For Python: Check for style guides, PEP 8 adherence, or project-specific conventions
|
||||
|
||||
**Key Standards to Apply:**
|
||||
|
||||
For **JavaScript/TypeScript** projects:
|
||||
- Use ES modules with proper import sorting and extensions
|
||||
- Prefer `function` keyword over arrow functions for top-level functions
|
||||
- Use explicit return type annotations for top-level functions
|
||||
- Follow proper React component patterns with explicit Props types
|
||||
- Use proper error handling patterns (avoid try/catch when possible)
|
||||
- Maintain consistent naming conventions
|
||||
|
||||
For **Go** projects:
|
||||
- Use `any` instead of `interface{}`
|
||||
- Follow console formatting for CLI output
|
||||
- Use semantic type aliases for domain concepts
|
||||
- Prefer small, focused files (200-500 lines ideal)
|
||||
- Use table-driven tests with descriptive names
|
||||
|
||||
For **Python** projects:
|
||||
- Follow PEP 8 style guide
|
||||
- Use type hints for function signatures
|
||||
- Prefer explicit over implicit code
|
||||
- Use list/dict comprehensions where they improve clarity (not complexity)
|
||||
|
||||
### 2.2 Simplification Principles
|
||||
|
||||
Apply these refinements to the recently modified code:
|
||||
|
||||
#### 1. Preserve Functionality
|
||||
- **NEVER** change what the code does - only how it does it
|
||||
- All original features, outputs, and behaviors must remain intact
|
||||
- Run tests before and after to ensure no behavioral changes
|
||||
|
||||
#### 2. Enhance Clarity
|
||||
- Reduce unnecessary complexity and nesting
|
||||
- Eliminate redundant code and abstractions
|
||||
- Improve readability through clear variable and function names
|
||||
- Consolidate related logic
|
||||
- Remove unnecessary comments that describe obvious code
|
||||
- **IMPORTANT**: Avoid nested ternary operators - prefer switch statements or if/else chains
|
||||
- Choose clarity over brevity - explicit code is often better than compact code
|
||||
|
||||
#### 3. Apply Project Standards
|
||||
- Use project-specific conventions and patterns
|
||||
- Follow established naming conventions
|
||||
- Apply consistent formatting
|
||||
- Use appropriate language features (modern syntax where beneficial)
|
||||
|
||||
#### 4. Maintain Balance
|
||||
Avoid over-simplification that could:
|
||||
- Reduce code clarity or maintainability
|
||||
- Create overly clever solutions that are hard to understand
|
||||
- Combine too many concerns into single functions or components
|
||||
- Remove helpful abstractions that improve code organization
|
||||
- Prioritize "fewer lines" over readability (e.g., nested ternaries, dense one-liners)
|
||||
- Make the code harder to debug or extend
|
||||
|
||||
### 2.3 Perform Code Analysis
|
||||
|
||||
For each changed file:
|
||||
|
||||
1. **Read the file contents** using the edit or view tool
|
||||
2. **Identify refactoring opportunities**:
|
||||
- Long functions that could be split
|
||||
- Duplicate code patterns
|
||||
- Complex conditionals that could be simplified
|
||||
- Unclear variable names
|
||||
- Missing or excessive comments
|
||||
- Non-standard patterns
|
||||
3. **Design the simplification**:
|
||||
- What specific changes will improve clarity?
|
||||
- How can complexity be reduced?
|
||||
- What patterns should be applied?
|
||||
- Will this maintain all functionality?
|
||||
|
||||
### 2.4 Apply Simplifications
|
||||
|
||||
Use the **edit** tool to modify files:
|
||||
|
||||
```bash
|
||||
# For each file with improvements:
|
||||
# 1. Read the current content
|
||||
# 2. Apply targeted edits to simplify code
|
||||
# 3. Ensure all functionality is preserved
|
||||
```
|
||||
|
||||
**Guidelines for edits:**
|
||||
- Make surgical, targeted changes
|
||||
- One logical improvement per edit (but batch multiple edits in a single response)
|
||||
- Preserve all original behavior
|
||||
- Keep changes focused on recently modified code
|
||||
- Don't refactor unrelated code unless it improves understanding of the changes
|
||||
|
||||
## Phase 3: Validate Changes
|
||||
|
||||
### 3.1 Run Tests
|
||||
|
||||
After making simplifications, run the project's test suite to ensure no functionality was broken:
|
||||
|
||||
```bash
|
||||
# For Go projects
|
||||
make test-unit
|
||||
|
||||
# For JavaScript/TypeScript projects
|
||||
npm test
|
||||
|
||||
# For Python projects
|
||||
pytest
|
||||
```
|
||||
|
||||
If tests fail:
|
||||
- Review the failures carefully
|
||||
- Revert changes that broke functionality
|
||||
- Adjust simplifications to preserve behavior
|
||||
- Re-run tests until they pass
|
||||
|
||||
### 3.2 Run Linters
|
||||
|
||||
Ensure code style is consistent:
|
||||
|
||||
```bash
|
||||
# For Go projects
|
||||
make lint
|
||||
|
||||
# For JavaScript/TypeScript projects
|
||||
npm run lint
|
||||
|
||||
# For Python projects
|
||||
flake8 . || pylint .
|
||||
```
|
||||
|
||||
Fix any linting issues introduced by the simplifications.
|
||||
|
||||
### 3.3 Check Build
|
||||
|
||||
Verify the project still builds successfully:
|
||||
|
||||
```bash
|
||||
# For Go projects
|
||||
make build
|
||||
|
||||
# For JavaScript/TypeScript projects
|
||||
npm run build
|
||||
|
||||
# For Python projects
|
||||
# (typically no build step, but check imports)
|
||||
python -m py_compile changed_files.py
|
||||
```
|
||||
|
||||
## Phase 4: Create GitHub Issue with Diff
|
||||
|
||||
### 4.1 Determine If Issue Is Needed
|
||||
|
||||
Only create an issue if:
|
||||
- ✅ You made actual code simplifications
|
||||
- ✅ All tests pass
|
||||
- ✅ Linting is clean
|
||||
- ✅ Build succeeds
|
||||
- ✅ Changes improve code quality without breaking functionality
|
||||
|
||||
If no improvements were made or changes broke tests, exit gracefully:
|
||||
|
||||
```
|
||||
✅ Code analyzed from last 24 hours.
|
||||
No simplifications needed - code already meets quality standards.
|
||||
```
|
||||
|
||||
### 4.2 Generate Git Diff
|
||||
|
||||
Before creating the issue, generate a properly formatted git diff that can be used to create a pull request:
|
||||
|
||||
```bash
|
||||
# Stage all changes if not already staged
|
||||
git add .
|
||||
|
||||
# Generate a complete unified diff of all staged changes
|
||||
git diff --cached > /tmp/code-simplification.diff
|
||||
|
||||
# Read the diff to include in the discussion
|
||||
cat /tmp/code-simplification.diff
|
||||
```
|
||||
|
||||
**Important**: The diff must be in standard unified diff format (git unified diff) that includes:
|
||||
- File headers with `diff --git a/path b/path`
|
||||
- Index lines with git hashes
|
||||
- `---` and `+++` lines showing old and new file paths
|
||||
- `@@` lines showing line numbers
|
||||
- Actual code changes with `-` for removed lines and `+` for added lines
|
||||
|
||||
This format is compatible with:
|
||||
- `git apply` command for direct application
|
||||
- GitHub's "Create PR from diff" functionality
|
||||
- GitHub Copilot for suggesting PR creation
|
||||
- Manual copy-paste into PR creation interface
|
||||
|
||||
### 4.3 Generate Issue Description
|
||||
|
||||
If creating an issue, use this structure:
|
||||
|
||||
```markdown
|
||||
## Code Simplification - [Date]
|
||||
|
||||
This discussion presents code simplifications that improve clarity, consistency, and maintainability while preserving all functionality.
|
||||
|
||||
### Files Simplified
|
||||
|
||||
- `path/to/file1.go` - [Brief description of improvements]
|
||||
- `path/to/file2.js` - [Brief description of improvements]
|
||||
|
||||
### Improvements Made
|
||||
|
||||
1. **Reduced Complexity**
|
||||
- Simplified nested conditionals in `file1.go`
|
||||
- Extracted helper function for repeated logic
|
||||
|
||||
2. **Enhanced Clarity**
|
||||
- Renamed variables for better readability
|
||||
- Removed redundant comments
|
||||
- Applied consistent naming conventions
|
||||
|
||||
3. **Applied Project Standards**
|
||||
- Used `function` keyword instead of arrow functions
|
||||
- Added explicit type annotations
|
||||
- Followed established patterns
|
||||
|
||||
### Changes Based On
|
||||
|
||||
Recent changes from:
|
||||
- #[PR_NUMBER] - [PR title]
|
||||
- Commit [SHORT_SHA] - [Commit message]
|
||||
|
||||
### Testing
|
||||
|
||||
- ✅ All tests pass
|
||||
- ✅ Linting passes
|
||||
- ✅ Build succeeds
|
||||
- ✅ No functional changes - behavior is identical
|
||||
|
||||
### Git Diff
|
||||
|
||||
Below is the complete diff that can be used to create a pull request. You can copy this diff and:
|
||||
- Use it with GitHub Copilot to create a PR
|
||||
- Apply it directly with `git apply`
|
||||
- Create a PR manually by copying the changes
|
||||
|
||||
```diff
|
||||
[PASTE THE COMPLETE GIT DIFF HERE]
|
||||
```
|
||||
|
||||
To apply this diff:
|
||||
|
||||
```bash
|
||||
# Save the diff to a file
|
||||
cat > /tmp/code-simplification.diff << 'EOF'
|
||||
[PASTE DIFF CONTENT]
|
||||
EOF
|
||||
|
||||
# Apply the diff
|
||||
git apply /tmp/code-simplification.diff
|
||||
|
||||
# Or create a PR from the current branch
|
||||
gh pr create --title "[code-simplifier] Code Simplification" --body "See discussion #[NUMBER]"
|
||||
```
|
||||
|
||||
### Review Focus
|
||||
|
||||
Please verify:
|
||||
- Functionality is preserved
|
||||
- Simplifications improve code quality
|
||||
- Changes align with project conventions
|
||||
- No unintended side effects
|
||||
|
||||
---
|
||||
|
||||
*Automated by Code Simplifier Agent - analyzing code from the last 24 hours*
|
||||
```
|
||||
|
||||
### 4.4 Use Safe Outputs
|
||||
|
||||
Create the issue using the safe-outputs configuration:
|
||||
|
||||
- Title will be prefixed with `[code-simplifier]`
|
||||
- Labeled with `refactoring`, `code-quality`, `automation`
|
||||
- Contains complete git diff for easy PR creation
|
||||
|
||||
## Important Guidelines
|
||||
|
||||
### Scope Control
|
||||
- **Focus on recent changes**: Only refine code modified in the last 24 hours
|
||||
- **Don't over-refactor**: Avoid touching unrelated code
|
||||
- **Preserve interfaces**: Don't change public APIs or exported functions
|
||||
- **Incremental improvements**: Make targeted, surgical changes
|
||||
|
||||
### Quality Standards
|
||||
- **Test first**: Always run tests after simplifications
|
||||
- **Preserve behavior**: Functionality must remain identical
|
||||
- **Follow conventions**: Apply project-specific patterns consistently
|
||||
- **Clear over clever**: Prioritize readability and maintainability
|
||||
|
||||
### Exit Conditions
|
||||
Exit gracefully without creating an issue if:
|
||||
- No code was changed in the last 24 hours
|
||||
- No simplifications are beneficial
|
||||
- Tests fail after changes
|
||||
- Build fails after changes
|
||||
- Changes are too risky or complex
|
||||
|
||||
### Success Metrics
|
||||
A successful simplification:
|
||||
- ✅ Improves code clarity without changing behavior
|
||||
- ✅ Passes all tests and linting
|
||||
- ✅ Applies project-specific conventions
|
||||
- ✅ Makes code easier to understand and maintain
|
||||
- ✅ Focuses on recently modified code
|
||||
- ✅ Provides clear documentation of changes
|
||||
|
||||
## Output Requirements
|
||||
|
||||
Your output MUST either:
|
||||
|
||||
1. **If no changes in last 24 hours**:
|
||||
```
|
||||
✅ No code changes detected in the last 24 hours.
|
||||
Code simplifier has nothing to process today.
|
||||
```
|
||||
|
||||
2. **If no simplifications beneficial**:
|
||||
```
|
||||
✅ Code analyzed from last 24 hours.
|
||||
No simplifications needed - code already meets quality standards.
|
||||
```
|
||||
|
||||
3. **If simplifications made**: Create an issue with the changes using safe-outputs, including:
|
||||
- Clear description of improvements
|
||||
- Complete git diff in proper format
|
||||
- Instructions for applying the diff or creating a PR
|
||||
|
||||
Begin your code simplification analysis now. Find recently modified code, assess simplification opportunities, apply improvements while preserving functionality, validate changes, and create an issue with a git diff if beneficial.
|
||||
||||||| base (original)
|
||||
---
|
||||
name: Code Simplifier
|
||||
description: Analyzes recently modified code and creates pull requests with simplifications that improve clarity, consistency, and maintainability while preserving functionality
|
||||
|
|
@ -443,389 +12,6 @@ permissions:
|
|||
|
||||
tracker-id: code-simplifier
|
||||
|
||||
imports:
|
||||
- shared/reporting.md
|
||||
|
||||
safe-outputs:
|
||||
create-pull-request:
|
||||
title-prefix: "[code-simplifier] "
|
||||
labels: [refactoring, code-quality, automation]
|
||||
reviewers: [copilot]
|
||||
expires: 7d
|
||||
|
||||
tools:
|
||||
github:
|
||||
toolsets: [default]
|
||||
|
||||
timeout-minutes: 30
|
||||
strict: true
|
||||
source: github/gh-aw/.github/workflows/code-simplifier.md@76d37d925abd44fee97379206f105b74b91a285b
|
||||
---
|
||||
|
||||
<!-- This prompt will be imported in the agentic workflow .github/workflows/code-simplifier.md at runtime. -->
|
||||
<!-- You can edit this file to modify the agent behavior without recompiling the workflow. -->
|
||||
|
||||
# Code Simplifier Agent
|
||||
|
||||
You are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality. Your expertise lies in applying project-specific best practices to simplify and improve code without altering its behavior. You prioritize readable, explicit code over overly compact solutions. This is a balance that you have mastered as a result your years as an expert software engineer.
|
||||
|
||||
## Your Mission
|
||||
|
||||
Analyze recently modified code from the last 24 hours and apply refinements that improve code quality while preserving all functionality. Create a pull request with the simplified code if improvements are found.
|
||||
|
||||
## Current Context
|
||||
|
||||
- **Repository**: ${{ github.repository }}
|
||||
- **Analysis Date**: $(date +%Y-%m-%d)
|
||||
- **Workspace**: ${{ github.workspace }}
|
||||
|
||||
## Phase 1: Identify Recently Modified Code
|
||||
|
||||
### 1.1 Find Recent Changes
|
||||
|
||||
Search for merged pull requests and commits from the last 24 hours:
|
||||
|
||||
```bash
|
||||
# Get yesterday's date in ISO format
|
||||
YESTERDAY=$(date -d '1 day ago' '+%Y-%m-%d' 2>/dev/null || date -v-1d '+%Y-%m-%d')
|
||||
|
||||
# List recent commits
|
||||
git log --since="24 hours ago" --pretty=format:"%H %s" --no-merges
|
||||
```
|
||||
|
||||
Use GitHub tools to:
|
||||
- Search for pull requests merged in the last 24 hours: `repo:${{ github.repository }} is:pr is:merged merged:>=${YESTERDAY}`
|
||||
- Get details of merged PRs to understand what files were changed
|
||||
- List commits from the last 24 hours to identify modified files
|
||||
|
||||
### 1.2 Extract Changed Files
|
||||
|
||||
For each merged PR or recent commit:
|
||||
- Use `pull_request_read` with `method: get_files` to list changed files
|
||||
- Use `get_commit` to see file changes in recent commits
|
||||
- Focus on source code files (`.go`, `.js`, `.ts`, `.tsx`, `.cjs`, `.py`, etc.)
|
||||
- Exclude test files, lock files, and generated files
|
||||
|
||||
### 1.3 Determine Scope
|
||||
|
||||
If **no files were changed in the last 24 hours**, exit gracefully without creating a PR:
|
||||
|
||||
```
|
||||
✅ No code changes detected in the last 24 hours.
|
||||
Code simplifier has nothing to process today.
|
||||
```
|
||||
|
||||
If **files were changed**, proceed to Phase 2.
|
||||
|
||||
## Phase 2: Analyze and Simplify Code
|
||||
|
||||
### 2.1 Review Project Standards
|
||||
|
||||
Before simplifying, review the project's coding standards from relevant documentation:
|
||||
|
||||
- For Go projects: Check `AGENTS.md`, `DEVGUIDE.md`, or similar files
|
||||
- For JavaScript/TypeScript: Look for `CLAUDE.md`, style guides, or coding conventions
|
||||
- For Python: Check for style guides, PEP 8 adherence, or project-specific conventions
|
||||
|
||||
**Key Standards to Apply:**
|
||||
|
||||
For **JavaScript/TypeScript** projects:
|
||||
- Use ES modules with proper import sorting and extensions
|
||||
- Prefer `function` keyword over arrow functions for top-level functions
|
||||
- Use explicit return type annotations for top-level functions
|
||||
- Follow proper React component patterns with explicit Props types
|
||||
- Use proper error handling patterns (avoid try/catch when possible)
|
||||
- Maintain consistent naming conventions
|
||||
|
||||
For **Go** projects:
|
||||
- Use `any` instead of `interface{}`
|
||||
- Follow console formatting for CLI output
|
||||
- Use semantic type aliases for domain concepts
|
||||
- Prefer small, focused files (200-500 lines ideal)
|
||||
- Use table-driven tests with descriptive names
|
||||
|
||||
For **Python** projects:
|
||||
- Follow PEP 8 style guide
|
||||
- Use type hints for function signatures
|
||||
- Prefer explicit over implicit code
|
||||
- Use list/dict comprehensions where they improve clarity (not complexity)
|
||||
|
||||
### 2.2 Simplification Principles
|
||||
|
||||
Apply these refinements to the recently modified code:
|
||||
|
||||
#### 1. Preserve Functionality
|
||||
- **NEVER** change what the code does - only how it does it
|
||||
- All original features, outputs, and behaviors must remain intact
|
||||
- Run tests before and after to ensure no behavioral changes
|
||||
|
||||
#### 2. Enhance Clarity
|
||||
- Reduce unnecessary complexity and nesting
|
||||
- Eliminate redundant code and abstractions
|
||||
- Improve readability through clear variable and function names
|
||||
- Consolidate related logic
|
||||
- Remove unnecessary comments that describe obvious code
|
||||
- **IMPORTANT**: Avoid nested ternary operators - prefer switch statements or if/else chains
|
||||
- Choose clarity over brevity - explicit code is often better than compact code
|
||||
|
||||
#### 3. Apply Project Standards
|
||||
- Use project-specific conventions and patterns
|
||||
- Follow established naming conventions
|
||||
- Apply consistent formatting
|
||||
- Use appropriate language features (modern syntax where beneficial)
|
||||
|
||||
#### 4. Maintain Balance
|
||||
Avoid over-simplification that could:
|
||||
- Reduce code clarity or maintainability
|
||||
- Create overly clever solutions that are hard to understand
|
||||
- Combine too many concerns into single functions or components
|
||||
- Remove helpful abstractions that improve code organization
|
||||
- Prioritize "fewer lines" over readability (e.g., nested ternaries, dense one-liners)
|
||||
- Make the code harder to debug or extend
|
||||
|
||||
### 2.3 Perform Code Analysis
|
||||
|
||||
For each changed file:
|
||||
|
||||
1. **Read the file contents** using the edit or view tool
|
||||
2. **Identify refactoring opportunities**:
|
||||
- Long functions that could be split
|
||||
- Duplicate code patterns
|
||||
- Complex conditionals that could be simplified
|
||||
- Unclear variable names
|
||||
- Missing or excessive comments
|
||||
- Non-standard patterns
|
||||
3. **Design the simplification**:
|
||||
- What specific changes will improve clarity?
|
||||
- How can complexity be reduced?
|
||||
- What patterns should be applied?
|
||||
- Will this maintain all functionality?
|
||||
|
||||
### 2.4 Apply Simplifications
|
||||
|
||||
Use the **edit** tool to modify files:
|
||||
|
||||
```bash
|
||||
# For each file with improvements:
|
||||
# 1. Read the current content
|
||||
# 2. Apply targeted edits to simplify code
|
||||
# 3. Ensure all functionality is preserved
|
||||
```
|
||||
|
||||
**Guidelines for edits:**
|
||||
- Make surgical, targeted changes
|
||||
- One logical improvement per edit (but batch multiple edits in a single response)
|
||||
- Preserve all original behavior
|
||||
- Keep changes focused on recently modified code
|
||||
- Don't refactor unrelated code unless it improves understanding of the changes
|
||||
|
||||
## Phase 3: Validate Changes
|
||||
|
||||
### 3.1 Run Tests
|
||||
|
||||
After making simplifications, run the project's test suite to ensure no functionality was broken:
|
||||
|
||||
```bash
|
||||
# For Go projects
|
||||
make test-unit
|
||||
|
||||
# For JavaScript/TypeScript projects
|
||||
npm test
|
||||
|
||||
# For Python projects
|
||||
pytest
|
||||
```
|
||||
|
||||
If tests fail:
|
||||
- Review the failures carefully
|
||||
- Revert changes that broke functionality
|
||||
- Adjust simplifications to preserve behavior
|
||||
- Re-run tests until they pass
|
||||
|
||||
### 3.2 Run Linters
|
||||
|
||||
Ensure code style is consistent:
|
||||
|
||||
```bash
|
||||
# For Go projects
|
||||
make lint
|
||||
|
||||
# For JavaScript/TypeScript projects
|
||||
npm run lint
|
||||
|
||||
# For Python projects
|
||||
flake8 . || pylint .
|
||||
```
|
||||
|
||||
Fix any linting issues introduced by the simplifications.
|
||||
|
||||
### 3.3 Check Build
|
||||
|
||||
Verify the project still builds successfully:
|
||||
|
||||
```bash
|
||||
# For Go projects
|
||||
make build
|
||||
|
||||
# For JavaScript/TypeScript projects
|
||||
npm run build
|
||||
|
||||
# For Python projects
|
||||
# (typically no build step, but check imports)
|
||||
python -m py_compile changed_files.py
|
||||
```
|
||||
|
||||
## Phase 4: Create Pull Request
|
||||
|
||||
### 4.1 Determine If PR Is Needed
|
||||
|
||||
Only create a PR if:
|
||||
- ✅ You made actual code simplifications
|
||||
- ✅ All tests pass
|
||||
- ✅ Linting is clean
|
||||
- ✅ Build succeeds
|
||||
- ✅ Changes improve code quality without breaking functionality
|
||||
|
||||
If no improvements were made or changes broke tests, exit gracefully:
|
||||
|
||||
```
|
||||
✅ Code analyzed from last 24 hours.
|
||||
No simplifications needed - code already meets quality standards.
|
||||
```
|
||||
|
||||
### 4.2 Generate PR Description
|
||||
|
||||
If creating a PR, use this structure:
|
||||
|
||||
```markdown
|
||||
## Code Simplification - [Date]
|
||||
|
||||
This PR simplifies recently modified code to improve clarity, consistency, and maintainability while preserving all functionality.
|
||||
|
||||
### Files Simplified
|
||||
|
||||
- `path/to/file1.go` - [Brief description of improvements]
|
||||
- `path/to/file2.js` - [Brief description of improvements]
|
||||
|
||||
### Improvements Made
|
||||
|
||||
1. **Reduced Complexity**
|
||||
- Simplified nested conditionals in `file1.go`
|
||||
- Extracted helper function for repeated logic
|
||||
|
||||
2. **Enhanced Clarity**
|
||||
- Renamed variables for better readability
|
||||
- Removed redundant comments
|
||||
- Applied consistent naming conventions
|
||||
|
||||
3. **Applied Project Standards**
|
||||
- Used `function` keyword instead of arrow functions
|
||||
- Added explicit type annotations
|
||||
- Followed established patterns
|
||||
|
||||
### Changes Based On
|
||||
|
||||
Recent changes from:
|
||||
- #[PR_NUMBER] - [PR title]
|
||||
- Commit [SHORT_SHA] - [Commit message]
|
||||
|
||||
### Testing
|
||||
|
||||
- ✅ All tests pass (`make test-unit`)
|
||||
- ✅ Linting passes (`make lint`)
|
||||
- ✅ Build succeeds (`make build`)
|
||||
- ✅ No functional changes - behavior is identical
|
||||
|
||||
### Review Focus
|
||||
|
||||
Please verify:
|
||||
- Functionality is preserved
|
||||
- Simplifications improve code quality
|
||||
- Changes align with project conventions
|
||||
- No unintended side effects
|
||||
|
||||
---
|
||||
|
||||
*Automated by Code Simplifier Agent - analyzing code from the last 24 hours*
|
||||
```
|
||||
|
||||
### 4.3 Use Safe Outputs
|
||||
|
||||
Create the pull request using the safe-outputs configuration:
|
||||
|
||||
- Title will be prefixed with `[code-simplifier]`
|
||||
- Labeled with `refactoring`, `code-quality`, `automation`
|
||||
- Assigned to `copilot` for review
|
||||
- Set as ready for review (not draft)
|
||||
|
||||
## Important Guidelines
|
||||
|
||||
### Scope Control
|
||||
- **Focus on recent changes**: Only refine code modified in the last 24 hours
|
||||
- **Don't over-refactor**: Avoid touching unrelated code
|
||||
- **Preserve interfaces**: Don't change public APIs or exported functions
|
||||
- **Incremental improvements**: Make targeted, surgical changes
|
||||
|
||||
### Quality Standards
|
||||
- **Test first**: Always run tests after simplifications
|
||||
- **Preserve behavior**: Functionality must remain identical
|
||||
- **Follow conventions**: Apply project-specific patterns consistently
|
||||
- **Clear over clever**: Prioritize readability and maintainability
|
||||
|
||||
### Exit Conditions
|
||||
Exit gracefully without creating a PR if:
|
||||
- No code was changed in the last 24 hours
|
||||
- No simplifications are beneficial
|
||||
- Tests fail after changes
|
||||
- Build fails after changes
|
||||
- Changes are too risky or complex
|
||||
|
||||
### Success Metrics
|
||||
A successful simplification:
|
||||
- ✅ Improves code clarity without changing behavior
|
||||
- ✅ Passes all tests and linting
|
||||
- ✅ Applies project-specific conventions
|
||||
- ✅ Makes code easier to understand and maintain
|
||||
- ✅ Focuses on recently modified code
|
||||
- ✅ Provides clear documentation of changes
|
||||
|
||||
## Output Requirements
|
||||
|
||||
Your output MUST either:
|
||||
|
||||
1. **If no changes in last 24 hours**:
|
||||
```
|
||||
✅ No code changes detected in the last 24 hours.
|
||||
Code simplifier has nothing to process today.
|
||||
```
|
||||
|
||||
2. **If no simplifications beneficial**:
|
||||
```
|
||||
✅ Code analyzed from last 24 hours.
|
||||
No simplifications needed - code already meets quality standards.
|
||||
```
|
||||
|
||||
3. **If simplifications made**: Create a PR with the changes using safe-outputs
|
||||
|
||||
Begin your code simplification analysis now. Find recently modified code, assess simplification opportunities, apply improvements while preserving functionality, validate changes, and create a PR if beneficial.
|
||||
=======
|
||||
---
|
||||
name: Code Simplifier
|
||||
description: Analyzes recently modified code and creates pull requests with simplifications that improve clarity, consistency, and maintainability while preserving functionality
|
||||
on:
|
||||
schedule: daily
|
||||
skip-if-match: 'is:pr is:open in:title "[code-simplifier]"'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
|
||||
tracker-id: code-simplifier
|
||||
|
||||
imports:
|
||||
- shared/activation-app.md
|
||||
- shared/reporting.md
|
||||
|
||||
safe-outputs:
|
||||
create-pull-request:
|
||||
|
|
@ -833,6 +19,8 @@ safe-outputs:
|
|||
labels: [refactoring, code-quality, automation]
|
||||
reviewers: [copilot]
|
||||
expires: 1d
|
||||
noop:
|
||||
report-as-issue: false
|
||||
|
||||
network:
|
||||
allowed:
|
||||
|
|
@ -1216,5 +404,4 @@ Begin your code simplification analysis now. Find recently modified code, assess
|
|||
|
||||
```json
|
||||
{"noop": {"message": "No action needed: [brief explanation of what was analyzed and why]"}}
|
||||
```
|
||||
>>>>>>> new (upstream)
|
||||
```
|
||||
1373
.github/workflows/compare-stats-anomaly-reporter.lock.yml
generated
vendored
Normal file
1373
.github/workflows/compare-stats-anomaly-reporter.lock.yml
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
191
.github/workflows/compare-stats-anomaly-reporter.md
vendored
Normal file
191
.github/workflows/compare-stats-anomaly-reporter.md
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
description: Analyze benchmark statistics from the latest 30 hours and publish bug/crash/anomaly summary as a GitHub Discussion
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 */12 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: read-all
|
||||
|
||||
strict: false
|
||||
timeout-minutes: 45
|
||||
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
- mtzguido.tplinkdns.com
|
||||
|
||||
tools:
|
||||
bash: [":*"]
|
||||
github:
|
||||
toolsets: [default]
|
||||
|
||||
safe-outputs:
|
||||
create-discussion:
|
||||
title-prefix: "[Compare Stats] "
|
||||
category: "agentic workflows"
|
||||
close-older-discussions: true
|
||||
missing-tool:
|
||||
create-issue: true
|
||||
noop:
|
||||
report-as-issue: false
|
||||
---
|
||||
|
||||
# Compare Stats Bug/Crash/Anomaly Reporter
|
||||
|
||||
Your name is ${{ github.workflow }}. You are a Z3 benchmarking analysis agent for `${{ github.repository }}`.
|
||||
|
||||
Analyze the benchmark statistics page below, focusing on results from the last 30 hours, then create a GitHub Discussion with a concise but actionable summary of:
|
||||
|
||||
- Bugs
|
||||
- Crashes
|
||||
- Anomalies
|
||||
|
||||
Source URL:
|
||||
`http://mtzguido.tplinkdns.com:8081/z3/`
|
||||
|
||||
Note: this endpoint is currently HTTP-only. Treat fetched data as non-sensitive benchmark telemetry and do not include secrets in requests or reports.
|
||||
Note: the workflow runs every 12 hours but analyzes 30 hours intentionally to provide overlap and avoid missing transient failures between runs.
|
||||
Overlapping windows are expected; `close-older-discussions: true` keeps only the latest report thread active.
|
||||
|
||||
## Requirements
|
||||
|
||||
### 1) Fetch and save the source page
|
||||
|
||||
Use bash to fetch the page into `/tmp/gh-aw/agent/benchmark_stats.html`.
|
||||
|
||||
Try this first:
|
||||
```bash
|
||||
curl -fsSL --max-time 60 "http://mtzguido.tplinkdns.com:8081/z3/" -o /tmp/gh-aw/agent/benchmark_stats.html
|
||||
```
|
||||
|
||||
If that fails, retry once with:
|
||||
```bash
|
||||
wget -q -T 60 -O /tmp/gh-aw/agent/benchmark_stats.html "http://mtzguido.tplinkdns.com:8081/z3/"
|
||||
```
|
||||
|
||||
If both fail, still create a discussion that explains the fetch failure, includes stderr output, and marks the report as incomplete.
|
||||
After a successful fetch, perform basic integrity checks before parsing:
|
||||
- file is non-empty
|
||||
- content includes `<html` and at least one `<table`
|
||||
- if checks fail, treat as suspicious/incomplete data and report this explicitly
|
||||
|
||||
### 2) Parse tabular data
|
||||
|
||||
Use Python to parse all tables from the HTML into normalized rows.
|
||||
|
||||
Use resilient parsing:
|
||||
- Prefer `pandas.read_html` when available.
|
||||
- If pandas fails, parse with `html.parser`/regex fallback.
|
||||
|
||||
Persist normalized JSON to `/tmp/gh-aw/agent/compare_stats_rows.json`.
|
||||
|
||||
### 3) Detect time window (last 30 hours)
|
||||
|
||||
Find candidate timestamp columns using case-insensitive column-name matches:
|
||||
- `time`, `timestamp`, `date`, `run`, `created`, `updated`
|
||||
|
||||
Parse datetimes with timezone handling if present. Use current UTC time and filter to rows where timestamp is within the past 30 hours.
|
||||
Treat naive timestamps as UTC.
|
||||
|
||||
If no timestamp can be extracted:
|
||||
- Report this limitation explicitly.
|
||||
- Continue analysis on all rows.
|
||||
- Mark the discussion as "time-window fallback".
|
||||
|
||||
### 4) Classify bugs/crashes/anomalies
|
||||
|
||||
Infer key columns using column-name heuristics:
|
||||
- status/result/outcome
|
||||
- benchmark/instance/file/name
|
||||
- set/suite/group/track/family
|
||||
- message/error/details/reason
|
||||
|
||||
Normalize status strings to lowercase.
|
||||
|
||||
#### Bugs / Crashes
|
||||
Classify a row as **crash/bug** if status/details contain terms like:
|
||||
- `crash`, `segfault`, `assert`, `abort`, `exception`, `error`, `failed`, `bug`
|
||||
|
||||
#### Anomalies
|
||||
At minimum, detect:
|
||||
|
||||
1. **Unknown-outlier anomaly** (required):
|
||||
- Within the same benchmark set/suite/group, if most rows are in `{sat, unsat, timeout}` but a minority are `unknown`, flag the `unknown` rows as anomalies.
|
||||
- Rationale: require enough samples for confidence and avoid flagging sets where `unknown` is common behavior. `0.4` caps unknown results to a minority, while `0.6` enforces a decisive majority of sat/unsat/timeout outcomes. Any remainder after those constraints is intentionally allowed for other statuses.
|
||||
- Use this threshold: `total_rows >= 4`, `unknown_count / total_rows <= 0.4`, and `(sat_count + unsat_count + timeout_count) / total_rows >= 0.6`.
|
||||
- If set/suite/group columns are missing, fallback grouping order is: directory prefix of benchmark path/name, then benchmark name prefix before first separator (`/`, `:`, `::`), then a single global group.
|
||||
|
||||
2. **Status divergence anomaly**:
|
||||
- Same benchmark name appears multiple times with conflicting non-timeout statuses (for example `sat` vs `unsat`).
|
||||
- Ignore timeout-only disagreements here; timeout behavior is covered under the repeated hard-failure anomaly section to reduce noise from transient runtime variance.
|
||||
|
||||
3. **Repeated hard-failure anomaly**:
|
||||
- Same benchmark appears repeatedly with crash/error-like status in the time window.
|
||||
|
||||
### 5) Generate discussion report
|
||||
|
||||
Create a GitHub Discussion using `create-discussion` safe output.
|
||||
|
||||
Use this structure:
|
||||
|
||||
```markdown
|
||||
### Compare Stats Analysis Report
|
||||
|
||||
**Source**: [benchmark statistics](http://mtzguido.tplinkdns.com:8081/z3/)
|
||||
**Workflow Run**: [#${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
||||
**Analysis Time (UTC)**: <timestamp>
|
||||
**Window**: last 30 hours (or fallback mode)
|
||||
|
||||
### Executive Summary
|
||||
|
||||
- Rows analyzed: N
|
||||
- Rows in 30h window: M (or "timestamp unavailable")
|
||||
- Bugs/crashes: B
|
||||
- Anomalies: A
|
||||
|
||||
### Bugs and Crashes
|
||||
|
||||
| Benchmark Set | Benchmark | Status | Details | Timestamp |
|
||||
|---|---|---|---|---|
|
||||
| ... |
|
||||
|
||||
### Anomalies
|
||||
|
||||
#### Unknown-Outlier Cases
|
||||
| Benchmark Set | Benchmark | Status | Peer Status Distribution | Timestamp |
|
||||
|---|---|---|---|---|
|
||||
| ... |
|
||||
|
||||
#### Status Divergences
|
||||
| Benchmark | Observed Statuses | Benchmark Set(s) | Timestamp(s) |
|
||||
|---|---|---|---|
|
||||
| ... |
|
||||
|
||||
#### Repeated Hard Failures
|
||||
| Benchmark | Failure Count | Representative Status/Details | Benchmark Set(s) |
|
||||
|---|---|---|---|
|
||||
| ... |
|
||||
|
||||
### Notes and Limitations
|
||||
- Mention parsing assumptions
|
||||
- Mention missing columns/timestamps if any
|
||||
|
||||
<details>
|
||||
<summary><b>Raw Extraction Summary</b></summary>
|
||||
|
||||
- Table count
|
||||
- Candidate columns used
|
||||
- Top status distribution
|
||||
- Up to 30 representative raw rows (sanitized)
|
||||
|
||||
</details>
|
||||
```
|
||||
|
||||
## Reporting Rules
|
||||
|
||||
- Be factual and concise.
|
||||
- Do not claim certainty when column mapping is heuristic.
|
||||
- If no bugs/crashes/anomalies are found, still create the discussion and explicitly state "No issues detected in analyzed window."
|
||||
- Do not open PRs or modify repository files.
|
||||
4
.github/workflows/coverage.yml
vendored
4
.github/workflows/coverage.yml
vendored
|
|
@ -89,13 +89,13 @@ jobs:
|
|||
id: date
|
||||
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/upload-artifact@v7
|
||||
- uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: coverage-${{steps.date.outputs.date}}
|
||||
path: ${{github.workspace}}/coverage.html
|
||||
retention-days: 4
|
||||
|
||||
- uses: actions/upload-artifact@v7
|
||||
- uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: coverage-details-${{steps.date.outputs.date}}
|
||||
path: ${{env.COV_DETAILS_PATH}}
|
||||
|
|
|
|||
2
.github/workflows/csa-analysis.md
vendored
2
.github/workflows/csa-analysis.md
vendored
|
|
@ -16,8 +16,6 @@ tools:
|
|||
github:
|
||||
toolsets: [default]
|
||||
bash: [":*"]
|
||||
glob: {}
|
||||
view: {}
|
||||
|
||||
safe-outputs:
|
||||
create-discussion:
|
||||
|
|
|
|||
4
.github/workflows/docs.yml
vendored
4
.github/workflows/docs.yml
vendored
|
|
@ -34,7 +34,7 @@ jobs:
|
|||
python3 mk_go_doc.py --output-dir=api/html/go --go-api-path=../src/api/go
|
||||
|
||||
- name: Upload Go Documentation
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: go-docs
|
||||
path: doc/api/html/go/
|
||||
|
|
@ -94,7 +94,7 @@ jobs:
|
|||
ocamldoc -html -d api/html/ml -sort -hide Z3 -I $( ocamlfind query zarith ) -I ../build-x64/api/ml ../build-x64/api/ml/z3enums.mli ../build-x64/api/ml/z3.mli
|
||||
|
||||
- name: Setup emscripten
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
uses: mymindstorm/setup-emsdk@v16
|
||||
with:
|
||||
no-install: true
|
||||
version: ${{env.EM_VERSION}}
|
||||
|
|
|
|||
19
.github/workflows/issue-backlog-processor.md
vendored
19
.github/workflows/issue-backlog-processor.md
vendored
|
|
@ -32,6 +32,8 @@ timeout-minutes: 60
|
|||
|
||||
Your name is ${{ github.workflow }}. You are an expert AI agent tasked with processing the backlog of open issues in the Z3 theorem prover repository `${{ github.repository }}`. Your mission is to analyze open issues systematically and help maintainers manage the backlog effectively by surfacing actionable insights and providing helpful comments.
|
||||
|
||||
> **CRITICAL**: You MUST call either `create-discussion` or `noop` before finishing, under all circumstances. Even if you only analyzed a small number of issues, always produce output. Never exit without calling one of these tools.
|
||||
|
||||
## Your Task
|
||||
|
||||
### 1. Initialize or Resume Progress (Cache Memory)
|
||||
|
|
@ -40,25 +42,28 @@ Check your cache memory for:
|
|||
- List of issue numbers already processed and commented on in previous runs
|
||||
- Issues previously flagged for closure, duplication, or merge
|
||||
- Date of last run
|
||||
- The batch cursor: the last issue number processed (used for pagination across runs)
|
||||
|
||||
If cache data exists:
|
||||
- Skip re-commenting on issues already commented in a recent run (within the last 4 days)
|
||||
- Re-evaluate previously flagged issues to see if their status has changed
|
||||
- Note any new issues that opened since the last run
|
||||
- Resume from where the previous run left off (use the stored batch cursor)
|
||||
|
||||
If this is the first run or memory is empty, initialize a fresh tracking structure.
|
||||
|
||||
### 2. Fetch Open Issues
|
||||
### 2. Fetch Open Issues (Batched)
|
||||
|
||||
Use the GitHub API to list all open issues in the repository:
|
||||
- Retrieve all open issues (paginate through all pages to get the full list)
|
||||
Use the GitHub API to list open issues in the repository. **Process at most 30 issues per run** to stay within context limits (this limit is based on the average size of Z3 issues including body text and inline code snippets; larger issues may require processing fewer):
|
||||
- Retrieve one page (30 issues) of open issues
|
||||
- Exclude pull requests (filter where `pull_request` is not present)
|
||||
- Sort by last updated date (most recently updated first)
|
||||
- If cache has a batch cursor from the last run, fetch the next page after that cursor; otherwise start from the most recently updated issues
|
||||
- For each issue, collect:
|
||||
- Issue number, title, body, labels, author
|
||||
- Date created and last updated
|
||||
- Number of comments
|
||||
- All comments (for issues with comments)
|
||||
- **Do NOT fetch comments for every issue up front.** Only fetch comments for a specific issue when at least one of the following is true: the body mentions a version number (potential closure), the title contains words like "duplicate", "same as", or "related to" (potential duplicate), or the issue has labels such as "question", "help wanted", or "wontfix" (potential closure/status change). Fetch comments lazily, one issue at a time, only when one of these criteria is met.
|
||||
- Any referenced pull requests, commits, or other issues
|
||||
|
||||
### 3. Analyze Each Issue
|
||||
|
|
@ -110,6 +115,8 @@ Add a comment to an issue if you have **genuinely useful and specific informatio
|
|||
|
||||
### 4. Create a Discussion with Findings
|
||||
|
||||
**MANDATORY**: You MUST call `create-discussion` now, even if you only analyzed a few issues or found nothing actionable. If there is genuinely nothing to report, call `noop` instead. Do not skip this step.
|
||||
|
||||
Create a GitHub Discussion summarizing the analysis results.
|
||||
|
||||
**Title:** "[Issue Backlog] Backlog Analysis - [Date]"
|
||||
|
|
@ -224,9 +231,13 @@ After completing the analysis, update cache memory with:
|
|||
- Issues flagged for closure, duplication, or merge
|
||||
- Date and timestamp of this run
|
||||
- Count of total issues analyzed
|
||||
- Batch cursor: the issue number of the last issue processed in this run, so the next run can continue from where this one left off
|
||||
|
||||
## Guidelines
|
||||
|
||||
- **Always produce output**: You MUST call `create-discussion` or `noop` before finishing — never exit silently. If in doubt about whether there is enough to report, call `create-discussion` with a brief summary.
|
||||
- **Batch processing**: Only analyze up to 30 issues per run. Store a cursor in cache memory so subsequent runs pick up where you left off.
|
||||
- **Lazy comment fetching**: Do NOT bulk-fetch all comments for all issues. Only fetch comments for a specific issue when one of these criteria is met: the body mentions a version number, the title contains duplicate/related keywords, or the issue has status-relevant labels (e.g., "question", "help wanted", "wontfix").
|
||||
- **Prioritize accuracy over coverage**: It is better to analyze 20 issues well than 200 issues poorly
|
||||
- **Be conservative on closures**: Incorrectly closing a valid issue is harmful; when in doubt, keep it open
|
||||
- **Respect the community**: Z3 is used by researchers, security engineers, and developers — treat all issues respectfully
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
pull-requests: write
|
||||
steps:
|
||||
- name: Mark all draft pull requests ready for review
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
|
|
|||
4
.github/workflows/memory-safety-report.md
vendored
4
.github/workflows/memory-safety-report.md
vendored
|
|
@ -30,8 +30,6 @@ tools:
|
|||
github:
|
||||
toolsets: [default, actions]
|
||||
bash: [":*"]
|
||||
glob: {}
|
||||
view: {}
|
||||
|
||||
safe-outputs:
|
||||
mentions: false
|
||||
|
|
@ -41,7 +39,7 @@ safe-outputs:
|
|||
title-prefix: "[Memory Safety] "
|
||||
category: "Agentic Workflows"
|
||||
close-older-discussions: true
|
||||
expires: 7
|
||||
expires: 7d
|
||||
missing-tool:
|
||||
create-issue: true
|
||||
noop:
|
||||
|
|
|
|||
4
.github/workflows/memory-safety.yml
vendored
4
.github/workflows/memory-safety.yml
vendored
|
|
@ -104,7 +104,7 @@ jobs:
|
|||
|
||||
- name: Upload ASan reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: asan-reports
|
||||
path: /tmp/asan-reports/
|
||||
|
|
@ -194,7 +194,7 @@ jobs:
|
|||
|
||||
- name: Upload UBSan reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ubsan-reports
|
||||
path: /tmp/ubsan-reports/
|
||||
|
|
|
|||
51
.github/workflows/nightly-validation.yml
vendored
51
.github/workflows/nightly-validation.yml
vendored
|
|
@ -665,6 +665,57 @@ jobs:
|
|||
pip install $wheel.FullName
|
||||
python -c "import z3; x = z3.Int('x'); s = z3.Solver(); s.add(x > 0); print('Result:', s.check()); print('Model:', s.model())"
|
||||
|
||||
validate-python-wheel-riscv64:
|
||||
name: "Validate Python wheel for RISC-V 64"
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Download RISC-V 64 Python wheel from release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
TAG="${{ github.event.inputs.release_tag }}"
|
||||
if [ -z "$TAG" ]; then
|
||||
TAG="Nightly"
|
||||
fi
|
||||
gh release download $TAG --pattern "*riscv64.whl" --dir wheels
|
||||
|
||||
- name: Verify wheel platform tag and contents
|
||||
run: |
|
||||
pip install wheel
|
||||
WHEEL_FILE=$(ls wheels/*.whl | head -n 1)
|
||||
echo "Wheel file: $WHEEL_FILE"
|
||||
|
||||
# Check that the wheel has a riscv64 platform tag
|
||||
WHEEL_NAME=$(basename $WHEEL_FILE)
|
||||
echo "Wheel name: $WHEEL_NAME"
|
||||
if echo "$WHEEL_NAME" | grep -q "riscv64"; then
|
||||
echo "riscv64 platform tag found"
|
||||
else
|
||||
echo "ERROR: riscv64 platform tag not found in wheel name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Inspect wheel contents
|
||||
python -m zipfile -l $WHEEL_FILE
|
||||
|
||||
# Verify wheel contains z3 library
|
||||
if python -m zipfile -l $WHEEL_FILE | grep -q "libz3"; then
|
||||
echo "libz3 found in wheel"
|
||||
else
|
||||
echo "ERROR: libz3 not found in wheel"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# MACOS DYLIB HEADERPAD VALIDATION
|
||||
# ============================================================================
|
||||
|
|
|
|||
221
.github/workflows/nightly.yml
vendored
221
.github/workflows/nightly.yml
vendored
|
|
@ -45,8 +45,21 @@ jobs:
|
|||
- name: Build
|
||||
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64
|
||||
|
||||
- name: Validate libz3.dylib and z3 architecture (must be x86_64)
|
||||
run: |
|
||||
set -e
|
||||
for f in build-dist/libz3.dylib build-dist/z3; do
|
||||
ARCH=$(lipo -archs "$f")
|
||||
echo "$f architecture: $ARCH"
|
||||
if [ "$ARCH" != "x86_64" ]; then
|
||||
echo "ERROR: $f has arch '$ARCH', expected 'x86_64' (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "OK: macOS x64 artifacts are x86_64"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: macOsBuild
|
||||
path: dist/*.zip
|
||||
|
|
@ -68,8 +81,21 @@ jobs:
|
|||
- name: Build
|
||||
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64
|
||||
|
||||
- name: Validate libz3.dylib and z3 architecture (must be arm64)
|
||||
run: |
|
||||
set -e
|
||||
for f in build-dist/libz3.dylib build-dist/z3; do
|
||||
ARCH=$(lipo -archs "$f")
|
||||
echo "$f architecture: $ARCH"
|
||||
if [ "$ARCH" != "arm64" ]; then
|
||||
echo "ERROR: $f has arch '$ARCH', expected 'arm64' (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "OK: macOS arm64 artifacts are arm64"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: MacArm64
|
||||
path: dist/*.zip
|
||||
|
|
@ -101,6 +127,17 @@ jobs:
|
|||
Z3_DIR=$(find . -maxdepth 1 -type d -name "z3-*" | head -n 1)
|
||||
echo "Z3_DIR=$Z3_DIR" >> $GITHUB_ENV
|
||||
|
||||
- name: Validate shipped libz3.dylib architecture (must be x86_64)
|
||||
run: |
|
||||
set -e
|
||||
DYLIB="artifacts/$Z3_DIR/bin/libz3.dylib"
|
||||
ARCH=$(lipo -archs "$DYLIB")
|
||||
echo "Shipped $DYLIB architecture: $ARCH"
|
||||
if [ "$ARCH" != "x86_64" ]; then
|
||||
echo "ERROR: x64 nightly zip contains '$ARCH' libz3.dylib (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Test install_name_tool with headerpad
|
||||
run: |
|
||||
cd artifacts/$Z3_DIR/bin
|
||||
|
|
@ -149,6 +186,17 @@ jobs:
|
|||
Z3_DIR=$(find . -maxdepth 1 -type d -name "z3-*" | head -n 1)
|
||||
echo "Z3_DIR=$Z3_DIR" >> $GITHUB_ENV
|
||||
|
||||
- name: Validate shipped libz3.dylib architecture (must be arm64)
|
||||
run: |
|
||||
set -e
|
||||
DYLIB="artifacts/$Z3_DIR/bin/libz3.dylib"
|
||||
ARCH=$(lipo -archs "$DYLIB")
|
||||
echo "Shipped $DYLIB architecture: $ARCH"
|
||||
if [ "$ARCH" != "arm64" ]; then
|
||||
echo "ERROR: arm64 nightly zip contains '$ARCH' libz3.dylib (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Test install_name_tool with headerpad
|
||||
run: |
|
||||
cd artifacts/$Z3_DIR/bin
|
||||
|
|
@ -198,7 +246,7 @@ jobs:
|
|||
run: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: UbuntuBuild
|
||||
path: dist/*.zip
|
||||
|
|
@ -233,7 +281,7 @@ jobs:
|
|||
python scripts/mk_unix_dist.py --nodotnet --arch=arm64
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: UbuntuArm64
|
||||
path: dist/*.zip
|
||||
|
|
@ -288,7 +336,7 @@ jobs:
|
|||
run: zip -r z3doc.zip doc/api
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: UbuntuDoc
|
||||
path: z3doc.zip
|
||||
|
|
@ -303,9 +351,17 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python environment
|
||||
run: |
|
||||
/opt/python/cp38-cp38/bin/python -m venv $PWD/env
|
||||
"$PYTHON" -m venv $PWD/env
|
||||
echo "$PWD/env/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install build tools
|
||||
|
|
@ -318,7 +374,7 @@ jobs:
|
|||
run: pip install ./src/api/python/wheelhouse/*.whl && python - <src/api/python/z3test.py z3 && python - <src/api/python/z3test.py z3num
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildAMD64
|
||||
path: src/api/python/wheelhouse/*.whl
|
||||
|
|
@ -341,9 +397,17 @@ jobs:
|
|||
mkdir -p /tmp/arm-toolchain/
|
||||
tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python environment
|
||||
run: |
|
||||
/opt/python/cp38-cp38/bin/python -m venv $PWD/env
|
||||
"$PYTHON" -m venv $PWD/env
|
||||
echo "$PWD/env/bin" >> $GITHUB_PATH
|
||||
echo "/tmp/arm-toolchain/bin" >> $GITHUB_PATH
|
||||
echo "/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin" >> $GITHUB_PATH
|
||||
|
|
@ -358,12 +422,120 @@ jobs:
|
|||
run: cd src/api/python && CC=aarch64-none-linux-gnu-gcc CXX=aarch64-none-linux-gnu-g++ AR=aarch64-none-linux-gnu-ar LD=aarch64-none-linux-gnu-ld Z3_CROSS_COMPILING=aarch64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildArm64
|
||||
path: src/api/python/wheelhouse/*.whl
|
||||
retention-days: 2
|
||||
|
||||
manylinux-python-riscv64:
|
||||
name: "Python bindings (manylinux RISC-V 64 cross)"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
container: quay.io/pypa/manylinux_2_28_x86_64:latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Download RISC-V toolchain
|
||||
run: curl -L -o /tmp/riscv-toolchain.tar.gz 'https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2024.09.03/riscv64-glibc-ubuntu-20.04-gcc-nightly-2024.09.03-nightly.tar.gz'
|
||||
|
||||
- name: Extract RISC-V toolchain
|
||||
run: |
|
||||
mkdir -p /tmp/riscv-toolchain/
|
||||
tar xf /tmp/riscv-toolchain.tar.gz -C /tmp/riscv-toolchain/ --strip-components=1
|
||||
|
||||
- name: Install MPFR 4 (required by RISC-V toolchain host binaries)
|
||||
run: |
|
||||
dnf install -y gmp-devel
|
||||
curl -L -o /tmp/mpfr.tar.xz https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.1.tar.xz
|
||||
tar xf /tmp/mpfr.tar.xz -C /tmp/
|
||||
cd /tmp/mpfr-4.2.1 && ./configure --prefix=/usr/local --disable-static && make -j$(nproc) && make install
|
||||
ldconfig
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python environment
|
||||
run: |
|
||||
"$PYTHON" -m venv $PWD/env
|
||||
echo "$PWD/env/bin" >> $GITHUB_PATH
|
||||
echo "/tmp/riscv-toolchain/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install build tools
|
||||
run: |
|
||||
echo $PATH
|
||||
stat $(which riscv64-unknown-linux-gnu-gcc)
|
||||
pip install build git+https://github.com/rhelmot/auditwheel
|
||||
|
||||
- name: Build wheels
|
||||
run: cd src/api/python && CC=riscv64-unknown-linux-gnu-gcc CXX=riscv64-unknown-linux-gnu-g++ AR=riscv64-unknown-linux-gnu-ar LD=riscv64-unknown-linux-gnu-ld Z3_CROSS_COMPILING=riscv64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildRiscv64
|
||||
path: src/api/python/wheelhouse/*.whl
|
||||
retention-days: 2
|
||||
|
||||
pyodide-python:
|
||||
name: "Python bindings (Pyodide)"
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup packages
|
||||
run: sudo apt-get update && sudo apt-get install -y python3-dev python3-pip python3-venv
|
||||
|
||||
- name: Create venv
|
||||
run: python3 -m venv ~/env
|
||||
|
||||
- name: Install pyodide
|
||||
run: ~/env/bin/pip install pyodide-build pyodide-cli
|
||||
|
||||
- name: Configure Emscripten
|
||||
run: |
|
||||
git clone https://github.com/emscripten-core/emsdk.git ~/emsdk
|
||||
cd ~/emsdk
|
||||
PYODIDE_EMSCRIPTEN_VERSION=$(~/env/bin/pyodide config get emscripten_version)
|
||||
./emsdk install ${PYODIDE_EMSCRIPTEN_VERSION}
|
||||
./emsdk activate ${PYODIDE_EMSCRIPTEN_VERSION}
|
||||
|
||||
- name: Build wheel
|
||||
run: |
|
||||
source ~/emsdk/emsdk_env.sh
|
||||
cd src/api/python
|
||||
CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" CXXFLAGS="${CXXFLAGS}" ~/env/bin/pyodide build --exports whole_archive
|
||||
env:
|
||||
CFLAGS: "-fexceptions -s DISABLE_EXCEPTION_CATCHING=0 -g2"
|
||||
LDFLAGS: "-fexceptions -s WASM_BIGINT"
|
||||
CXXFLAGS: "-fexceptions -s DISABLE_EXCEPTION_CATCHING=0"
|
||||
|
||||
- name: Setup env-pyodide
|
||||
run: |
|
||||
source ~/env/bin/activate
|
||||
source ~/emsdk/emsdk_env.sh
|
||||
pyodide venv ~/env-pyodide
|
||||
|
||||
- name: Test wheel
|
||||
run: |
|
||||
~/env-pyodide/bin/pip install src/api/python/dist/*.whl
|
||||
~/env-pyodide/bin/python src/api/python/z3test.py z3
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: PyodidePythonBuild
|
||||
path: src/api/python/dist/*.whl
|
||||
retention-days: 2
|
||||
|
||||
windows-build-x64:
|
||||
name: "Windows x64 build"
|
||||
runs-on: windows-latest
|
||||
|
|
@ -384,7 +556,7 @@ jobs:
|
|||
python scripts\mk_win_dist.py --x64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: WindowsBuild-x64
|
||||
path: dist/*.zip
|
||||
|
|
@ -410,7 +582,7 @@ jobs:
|
|||
python scripts\mk_win_dist.py --x86-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: WindowsBuild-x86
|
||||
path: dist/*.zip
|
||||
|
|
@ -436,7 +608,7 @@ jobs:
|
|||
python scripts\mk_win_dist_cmake.py --arm64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }} --zip
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: WindowsBuild-arm64
|
||||
path: dist/arm64/*.zip
|
||||
|
|
@ -496,7 +668,7 @@ jobs:
|
|||
path: package
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@v2
|
||||
uses: nuget/setup-nuget@v4
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
|
|
@ -513,7 +685,7 @@ jobs:
|
|||
nuget pack out\Microsoft.Z3.sym.nuspec -Version ${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}.${{ github.run_number }} -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: NuGet
|
||||
path: |
|
||||
|
|
@ -541,7 +713,7 @@ jobs:
|
|||
path: package
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@v2
|
||||
uses: nuget/setup-nuget@v4
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
|
|
@ -558,7 +730,7 @@ jobs:
|
|||
nuget pack out\Microsoft.Z3.x86.sym.nuspec -Version ${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}.${{ github.run_number }} -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: NuGet32
|
||||
path: |
|
||||
|
|
@ -568,7 +740,7 @@ jobs:
|
|||
|
||||
python-package:
|
||||
name: "Python packaging"
|
||||
needs: [mac-build-x64, mac-build-arm64, windows-build-x64, windows-build-x86, windows-build-arm64, manylinux-python-amd64, manylinux-python-arm64]
|
||||
needs: [mac-build-x64, mac-build-arm64, windows-build-x64, windows-build-x86, windows-build-arm64, manylinux-python-amd64, manylinux-python-arm64, manylinux-python-riscv64, pyodide-python]
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
|
@ -621,6 +793,18 @@ jobs:
|
|||
name: ManyLinuxPythonBuildArm64
|
||||
path: artifacts
|
||||
|
||||
- name: Download ManyLinux RISC-V 64 Build
|
||||
uses: actions/download-artifact@v8.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildRiscv64
|
||||
path: artifacts
|
||||
|
||||
- name: Download Pyodide Build
|
||||
uses: actions/download-artifact@v8.0.1
|
||||
with:
|
||||
name: PyodidePythonBuild
|
||||
path: artifacts
|
||||
|
||||
- name: Extract builds
|
||||
run: |
|
||||
cd artifacts
|
||||
|
|
@ -651,7 +835,7 @@ jobs:
|
|||
cp artifacts/*.whl src/api/python/dist/.
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: PythonPackages
|
||||
path: src/api/python/dist/*
|
||||
|
|
@ -759,4 +943,3 @@ jobs:
|
|||
with:
|
||||
packages-dir: dist
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
||||
|
|
|
|||
20
.github/workflows/nuget-build.yml
vendored
20
.github/workflows/nuget-build.yml
vendored
|
|
@ -34,7 +34,7 @@ jobs:
|
|||
python scripts\mk_win_dist.py --x64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ github.event.inputs.version || '4.17.0' }} --zip
|
||||
|
||||
- name: Upload Windows x64 artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: windows-x64
|
||||
path: dist/*.zip
|
||||
|
|
@ -58,7 +58,7 @@ jobs:
|
|||
python scripts\mk_win_dist.py --x86-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ github.event.inputs.version || '4.17.0' }} --zip
|
||||
|
||||
- name: Upload Windows x86 artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: windows-x86
|
||||
path: dist/*.zip
|
||||
|
|
@ -82,7 +82,7 @@ jobs:
|
|||
python scripts\mk_win_dist_cmake.py --arm64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ github.event.inputs.version || '4.17.0' }} --zip
|
||||
|
||||
- name: Upload Windows ARM64 artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: windows-arm64
|
||||
path: build-dist\arm64\dist\*.zip
|
||||
|
|
@ -103,7 +103,7 @@ jobs:
|
|||
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk
|
||||
|
||||
- name: Upload Ubuntu artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ubuntu
|
||||
path: dist/*.zip
|
||||
|
|
@ -124,7 +124,7 @@ jobs:
|
|||
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk
|
||||
|
||||
- name: Upload macOS x64 artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: macos-x64
|
||||
path: dist/*.zip
|
||||
|
|
@ -145,7 +145,7 @@ jobs:
|
|||
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64
|
||||
|
||||
- name: Upload macOS ARM64 artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: macos-arm64
|
||||
path: dist/*.zip
|
||||
|
|
@ -181,7 +181,7 @@ jobs:
|
|||
ls -la package-files/
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@v2
|
||||
uses: nuget/setup-nuget@v4
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ jobs:
|
|||
nuget pack out\Microsoft.Z3.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
|
||||
|
||||
- name: Upload NuGet package
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: nuget-x64
|
||||
path: |
|
||||
|
|
@ -230,7 +230,7 @@ jobs:
|
|||
run: find packages -type f
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@v2
|
||||
uses: nuget/setup-nuget@v4
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ jobs:
|
|||
nuget pack out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
|
||||
|
||||
- name: Upload NuGet package
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: nuget-x86
|
||||
path: |
|
||||
|
|
|
|||
4
.github/workflows/ocaml.yaml
vendored
4
.github/workflows/ocaml.yaml
vendored
|
|
@ -21,7 +21,7 @@ jobs:
|
|||
|
||||
# Cache ccache (shared across runs)
|
||||
- name: Cache ccache
|
||||
uses: actions/cache@v5.0.4
|
||||
uses: actions/cache@v5.0.5
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{ runner.os }}-ccache-${{ github.sha }}
|
||||
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
|
||||
# Cache opam (compiler + packages)
|
||||
- name: Cache opam
|
||||
uses: actions/cache@v5.0.4
|
||||
uses: actions/cache@v5.0.5
|
||||
with:
|
||||
path: ~/.opam
|
||||
key: ${{ runner.os }}-opam-${{ matrix.ocaml-version }}-${{ github.sha }}
|
||||
|
|
|
|||
20
.github/workflows/ostrich-benchmark.md
vendored
20
.github/workflows/ostrich-benchmark.md
vendored
|
|
@ -8,7 +8,10 @@ on:
|
|||
|
||||
permissions: read-all
|
||||
|
||||
network: defaults
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
- api.nuget.org
|
||||
|
||||
tools:
|
||||
bash: true
|
||||
|
|
@ -85,6 +88,8 @@ echo "Found Microsoft.Z3.dll at: $Z3_DOTNET_DLL"
|
|||
|
||||
If the build fails, report the error clearly and exit without proceeding.
|
||||
|
||||
Once the binary is confirmed working, call the `noop` safe-output tool with the message `"Z3 built successfully from the c3 branch. Starting ZIPT build and benchmark — results will be posted as a GitHub Discussion once complete."` This keepalive call refreshes the safe-output MCP session before the long build and benchmark phases begin, preventing a session timeout.
|
||||
|
||||
## Phase 2a: Clone and Build ZIPT
|
||||
|
||||
Clone the ZIPT solver from the `parikh` branch and compile it against the Z3 .NET bindings built in Phase 1.
|
||||
|
|
@ -150,6 +155,8 @@ if [ "$TOTAL_FILES" -eq 0 ]; then
|
|||
fi
|
||||
```
|
||||
|
||||
Once the benchmark files are confirmed, call the `noop` safe-output tool with the message `"Benchmark files ready: <TOTAL_FILES> Ostrich .smt2 files extracted. Starting benchmark run — this may take over an hour."` This second keepalive refreshes the safe-output MCP session immediately before the long per-file benchmark loop begins.
|
||||
|
||||
## Phase 3: Run Benchmarks
|
||||
|
||||
Run every file from `/tmp/all_ostrich_files.txt` with both Z3 string solvers and ZIPT. Use a **5-second timeout** per run.
|
||||
|
|
@ -402,3 +409,14 @@ Post the Markdown report as a new GitHub Discussion using the `create-discussion
|
|||
- **Handle build failures gracefully**: If Z3 fails to build, report the error and create a brief discussion noting the build failure. If ZIPT fails to build, continue with only the seq/nseq columns and note `n/a` for ZIPT results.
|
||||
- **Large report**: Always put the per-file table in a `<details>` collapsible section since there may be many files.
|
||||
- **Progress logging**: Print a line per file as you run it (e.g., `[N] [filename] seq=...`) so the workflow log shows progress even for large benchmark sets.
|
||||
|
||||
## Safe Output Guarantee
|
||||
|
||||
You **MUST** call either `create_discussion` or `noop` before the workflow ends, regardless of what happened during execution:
|
||||
|
||||
- **Build succeeded, benchmarks ran**: Call `create_discussion` with the full report.
|
||||
- **Build succeeded, benchmarks partially ran**: Call `create_discussion` with whatever results were collected and a note about what could not be completed.
|
||||
- **Z3 build failed**: Call `noop` with a brief message describing the build error.
|
||||
- **No benchmarks could be run**: Call `noop` with a summary of what failed and why.
|
||||
|
||||
Failing to produce any safe output triggers an automatic workflow-failure issue that clutters the repository.
|
||||
|
|
|
|||
669
.github/workflows/qf-s-benchmark.md
vendored
669
.github/workflows/qf-s-benchmark.md
vendored
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
description: Run Z3 string solver benchmarks (seq vs nseq) on QF_S test suite from the c3 branch and post results as a GitHub discussion
|
||||
description: Benchmark Z3 seq vs nseq string solvers on QF_S test suite from the c3 branch and post results as a GitHub discussion
|
||||
|
||||
on:
|
||||
schedule:
|
||||
|
|
@ -17,7 +17,7 @@ tools:
|
|||
|
||||
safe-outputs:
|
||||
create-discussion:
|
||||
title-prefix: "[ZIPT Benchmark] "
|
||||
title-prefix: "[QF_S Benchmark] "
|
||||
category: "Agentic Workflows"
|
||||
close-older-discussions: true
|
||||
missing-tool:
|
||||
|
|
@ -25,7 +25,7 @@ safe-outputs:
|
|||
noop:
|
||||
report-as-issue: false
|
||||
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Checkout c3 branch
|
||||
|
|
@ -37,437 +37,368 @@ steps:
|
|||
|
||||
---
|
||||
|
||||
# QF_S String Solver Benchmark
|
||||
|
||||
# ZIPT String Solver Benchmark
|
||||
## Job Description
|
||||
|
||||
You are an AI agent that benchmarks Z3 string solvers (`seq` and `nseq`) and the standalone ZIPT solver on QF_S SMT-LIB2 benchmarks from the `c3` branch, and publishes a summary report as a GitHub discussion.
|
||||
Your name is ${{ github.workflow }}. You are an expert performance analyst for the Z3 theorem prover, specializing in the string/sequence theory. Your task is to benchmark the `seq` solver (classical string theory) against the `nseq` solver (ZIPT-based string theory) on the QF_S test suite from the `c3` branch, and post a structured report as a GitHub Discussion.
|
||||
|
||||
## Context
|
||||
The workspace already contains the `c3` branch (checked out by the preceding workflow step).
|
||||
|
||||
- **Repository**: ${{ github.repository }}
|
||||
- **Workspace**: ${{ github.workspace }}
|
||||
- **Branch**: c3 (already checked out by the workflow setup step)
|
||||
## Phase 1: Set Up the Build Environment
|
||||
|
||||
## Phase 1: Build Z3
|
||||
|
||||
Build Z3 from the checked-out `c3` branch using CMake + Ninja, including the .NET bindings required by ZIPT.
|
||||
Install required build tools:
|
||||
|
||||
```bash
|
||||
cd ${{ github.workspace }}
|
||||
|
||||
# Install build dependencies if missing
|
||||
sudo apt-get install -y ninja-build cmake python3 zstd dotnet-sdk-8.0 2>/dev/null || true
|
||||
|
||||
# Configure the build in Debug mode to enable assertions and tracing
|
||||
# (Debug mode is required for -tr: trace flags to produce meaningful output)
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DZ3_BUILD_DOTNET_BINDINGS=ON 2>&1 | tail -20
|
||||
|
||||
# Build z3 binary and .NET bindings (this takes ~15-17 minutes)
|
||||
ninja z3 2>&1 | tail -30
|
||||
ninja build_z3_dotnet_bindings 2>&1 | tail -20
|
||||
|
||||
# Verify the build succeeded
|
||||
./z3 --version
|
||||
|
||||
# Locate the Microsoft.Z3.dll produced by the build
|
||||
Z3_DOTNET_DLL=$(find . -name "Microsoft.Z3.dll" -not -path "*/obj/*" | head -1)
|
||||
if [ -z "$Z3_DOTNET_DLL" ]; then
|
||||
echo "ERROR: Microsoft.Z3.dll not found after build"
|
||||
exit 1
|
||||
fi
|
||||
echo "Found Microsoft.Z3.dll at: $Z3_DOTNET_DLL"
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake ninja-build python3 python3-pip time
|
||||
```
|
||||
|
||||
If the build fails, report the error clearly and exit without proceeding.
|
||||
|
||||
## Phase 2a: Clone and Build ZIPT
|
||||
|
||||
Clone the ZIPT solver from the `parikh` branch and compile it against the Z3 .NET bindings built in Phase 1.
|
||||
Verify tools:
|
||||
|
||||
```bash
|
||||
cd ${{ github.workspace }}
|
||||
cmake --version
|
||||
ninja --version
|
||||
python3 --version
|
||||
```
|
||||
|
||||
# Re-locate the Microsoft.Z3.dll if needed
|
||||
Z3_DOTNET_DLL=$(find build -name "Microsoft.Z3.dll" -not -path "*/obj/*" | head -1)
|
||||
Z3_LIB_DIR=${{ github.workspace }}/build
|
||||
## Phase 2: Build Z3 in Release Mode
|
||||
|
||||
# Clone ZIPT (parikh branch)
|
||||
git clone --depth=1 --branch parikh https://github.com/CEisenhofer/ZIPT.git /tmp/zipt
|
||||
Build Z3 in Release mode for accurate benchmark performance numbers and lower memory usage. Running `ninja` in the background with `&` is not allowed — concurrent C++ compilation and LLM inference can exhaust available RAM and kill the agent process.
|
||||
|
||||
# Patch ZIPT.csproj to point at the freshly built Microsoft.Z3.dll
|
||||
# (the repo has a Windows-relative hardcoded path that won't exist here)
|
||||
sed -i "s|<HintPath>.*</HintPath>|<HintPath>$Z3_DOTNET_DLL</HintPath>|" /tmp/zipt/ZIPT/ZIPT.csproj
|
||||
```bash
|
||||
mkdir -p /tmp/z3-build
|
||||
cd /tmp/z3-build
|
||||
cmake "$GITHUB_WORKSPACE" \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DZ3_BUILD_TEST_EXECUTABLES=OFF \
|
||||
2>&1 | tee /tmp/z3-cmake.log
|
||||
ninja -j2 z3 2>&1 | tee /tmp/z3-build.log
|
||||
```
|
||||
|
||||
# Build ZIPT in Release mode
|
||||
cd /tmp/zipt/ZIPT
|
||||
dotnet build --configuration Release 2>&1 | tail -20
|
||||
Verify the binary was built:
|
||||
|
||||
# Locate the built ZIPT.dll
|
||||
ZIPT_DLL=$(find /tmp/zipt/ZIPT/bin/Release -name "ZIPT.dll" | head -1)
|
||||
if [ -z "$ZIPT_DLL" ]; then
|
||||
echo "ERROR: ZIPT.dll not found after build"
|
||||
exit 1
|
||||
```bash
|
||||
/tmp/z3-build/z3 --version
|
||||
```
|
||||
|
||||
If the build fails, report it immediately and stop.
|
||||
|
||||
Once the binary is confirmed working, call the `noop` safe-output tool with the message `"Z3 built successfully from the c3 branch. Benchmark starting — results will be posted as a GitHub Discussion once complete."` This keepalive call refreshes the safe-output MCP session before the long benchmark run begins, preventing a session timeout.
|
||||
|
||||
## Phase 3: Discover QF_S Benchmark Files
|
||||
|
||||
Find all `.smt2` benchmark files in the workspace that belong to the QF_S logic:
|
||||
|
||||
```bash
|
||||
# Search for explicit QF_S logic declarations
|
||||
grep -rl 'QF_S' "$GITHUB_WORKSPACE" --include='*.smt2' 2>/dev/null > /tmp/qf_s_files.txt
|
||||
|
||||
# Also look in dedicated benchmark directories
|
||||
find "$GITHUB_WORKSPACE" \
|
||||
\( -path "*/QF_S/*" -o -path "*/qf_s/*" -o -path "*/benchmarks/*" \) \
|
||||
-name '*.smt2' 2>/dev/null >> /tmp/qf_s_files.txt
|
||||
|
||||
# Deduplicate
|
||||
sort -u /tmp/qf_s_files.txt -o /tmp/qf_s_files.txt
|
||||
|
||||
TOTAL=$(wc -l < /tmp/qf_s_files.txt)
|
||||
echo "Found $TOTAL QF_S benchmark files"
|
||||
head -20 /tmp/qf_s_files.txt
|
||||
```
|
||||
|
||||
If fewer than 5 files are found, also scan the entire workspace for any `.smt2` file that exercises string constraints:
|
||||
|
||||
```bash
|
||||
if [ "$TOTAL" -lt 5 ]; then
|
||||
grep -rl 'declare.*String\|str\.\|seq\.' "$GITHUB_WORKSPACE" \
|
||||
--include='*.smt2' 2>/dev/null >> /tmp/qf_s_files.txt
|
||||
sort -u /tmp/qf_s_files.txt -o /tmp/qf_s_files.txt
|
||||
TOTAL=$(wc -l < /tmp/qf_s_files.txt)
|
||||
echo "After extended search: $TOTAL files"
|
||||
fi
|
||||
echo "ZIPT binary: $ZIPT_DLL"
|
||||
```
|
||||
|
||||
# Make libz3.so visible to the .NET runtime at ZIPT startup
|
||||
ZIPT_OUT_DIR=$(dirname "$ZIPT_DLL")
|
||||
if cp "$Z3_LIB_DIR/libz3.so" "$ZIPT_OUT_DIR/" 2>/dev/null; then
|
||||
echo "Copied libz3.so to $ZIPT_OUT_DIR"
|
||||
Cap the benchmark set to keep total runtime under 60 minutes:
|
||||
|
||||
```bash
|
||||
# Use at most 300 files; take a random sample if more are available
|
||||
if [ "$TOTAL" -gt 300 ]; then
|
||||
shuf -n 300 /tmp/qf_s_files.txt > /tmp/qf_s_sample.txt
|
||||
else
|
||||
echo "WARNING: could not copy libz3.so to $ZIPT_OUT_DIR — setting LD_LIBRARY_PATH fallback"
|
||||
cp /tmp/qf_s_files.txt /tmp/qf_s_sample.txt
|
||||
fi
|
||||
export LD_LIBRARY_PATH="$Z3_LIB_DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
echo "ZIPT build complete."
|
||||
SAMPLE=$(wc -l < /tmp/qf_s_sample.txt)
|
||||
echo "Running benchmarks on $SAMPLE files"
|
||||
```
|
||||
|
||||
If the ZIPT build fails, note the error in the report but continue with the Z3-only benchmark columns.
|
||||
## Phase 4: Run Benchmarks — seq vs nseq
|
||||
|
||||
## Phase 2b: Extract and Select Benchmark Files
|
||||
|
||||
Extract the QF_S benchmark archive and randomly select 50 files.
|
||||
Run each benchmark with both solvers. Use a per-file timeout of 5 seconds. Set Z3's internal timeout to 4 seconds so it exits cleanly before the shell timeout fires.
|
||||
|
||||
```bash
|
||||
cd ${{ github.workspace }}
|
||||
Z3=/tmp/z3-build/z3
|
||||
TIMEOUT_SEC=5
|
||||
Z3_TIMEOUT_SEC=4
|
||||
RESULTS=/tmp/benchmark-results.csv
|
||||
|
||||
# Extract the archive
|
||||
mkdir -p /tmp/qfs_benchmarks
|
||||
tar --zstd -xf tests/QF_S.tar.zst -C /tmp/qfs_benchmarks
|
||||
echo "file,seq_result,seq_time_ms,nseq_result,nseq_time_ms" > "$RESULTS"
|
||||
|
||||
# List all .smt2 files
|
||||
find /tmp/qfs_benchmarks -name "*.smt2" -type f > /tmp/all_qfs_files.txt
|
||||
TOTAL_FILES=$(wc -l < /tmp/all_qfs_files.txt)
|
||||
echo "Total QF_S files: $TOTAL_FILES"
|
||||
total=0
|
||||
done_count=0
|
||||
while IFS= read -r smt_file; do
|
||||
total=$((total + 1))
|
||||
|
||||
# Randomly select 200 files
|
||||
shuf -n 200 /tmp/all_qfs_files.txt > /tmp/selected_files.txt
|
||||
echo "Selected 200 files for benchmarking"
|
||||
cat /tmp/selected_files.txt
|
||||
# Run with seq solver; capture both stdout (z3 output) and stderr (time output)
|
||||
SEQ_OUT=$({ time timeout "$TIMEOUT_SEC" "$Z3" \
|
||||
smt.string_solver=seq \
|
||||
-T:"$Z3_TIMEOUT_SEC" \
|
||||
"$smt_file" 2>/dev/null; } 2>&1)
|
||||
SEQ_RESULT=$(echo "$SEQ_OUT" | grep -E '^(sat|unsat|unknown)' | head -1)
|
||||
SEQ_MS=$(echo "$SEQ_OUT" | grep real | awk '{split($2,a,"m"); split(a[2],b,"s"); printf "%d", (a[1]*60+b[1])*1000}')
|
||||
[ -z "$SEQ_RESULT" ] && SEQ_RESULT="timeout"
|
||||
[ -z "$SEQ_MS" ] && SEQ_MS=$((TIMEOUT_SEC * 1000))
|
||||
|
||||
# Run with nseq solver; same structure
|
||||
NSEQ_OUT=$({ time timeout "$TIMEOUT_SEC" "$Z3" \
|
||||
smt.string_solver=nseq \
|
||||
-T:"$Z3_TIMEOUT_SEC" \
|
||||
"$smt_file" 2>/dev/null; } 2>&1)
|
||||
NSEQ_RESULT=$(echo "$NSEQ_OUT" | grep -E '^(sat|unsat|unknown)' | head -1)
|
||||
NSEQ_MS=$(echo "$NSEQ_OUT" | grep real | awk '{split($2,a,"m"); split(a[2],b,"s"); printf "%d", (a[1]*60+b[1])*1000}')
|
||||
[ -z "$NSEQ_RESULT" ] && NSEQ_RESULT="timeout"
|
||||
[ -z "$NSEQ_MS" ] && NSEQ_MS=$((TIMEOUT_SEC * 1000))
|
||||
|
||||
SHORT=$(basename "$smt_file")
|
||||
echo "$SHORT,$SEQ_RESULT,$SEQ_MS,$NSEQ_RESULT,$NSEQ_MS" >> "$RESULTS"
|
||||
|
||||
done_count=$((done_count + 1))
|
||||
if [ $((done_count % 50)) -eq 0 ]; then
|
||||
echo "Progress: $done_count / $SAMPLE files completed"
|
||||
fi
|
||||
done < /tmp/qf_s_sample.txt
|
||||
|
||||
echo "Benchmark run complete: $done_count files"
|
||||
```
|
||||
|
||||
## Phase 3: Run Benchmarks
|
||||
## Phase 5: Collect Seq Traces for Interesting Cases
|
||||
|
||||
Run each of the 200 selected files with both Z3 string solvers and ZIPT. Use a 5-second timeout for seq and a 10-second timeout for nseq and ZIPT.
|
||||
|
||||
For each file, run:
|
||||
1. `z3 smt.string_solver=seq -tr:seq -T:5 <file>` — seq solver with sequence-solver tracing enabled; rename the `.z3-trace` output after each run so it is not overwritten. Use `-T:5` when tracing to cap trace size.
|
||||
2. `z3 smt.string_solver=nseq -T:5 <file>` — nseq solver without tracing (timing only).
|
||||
3. `dotnet <ZIPT.dll> -t:5000 <file>` — ZIPT solver (milliseconds).
|
||||
|
||||
Capture:
|
||||
- **Verdict**: `sat`, `unsat`, `unknown`, `timeout` (if exit code indicates timeout or process is killed), or `bug` (if a solver crashes / produces a non-standard result)
|
||||
- **Time** (seconds): wall-clock time for the run
|
||||
- A row is flagged `SOUNDNESS_DISAGREEMENT` when any two solvers that both produced a definitive answer (sat/unsat) disagree
|
||||
|
||||
Use a bash script to automate this:
|
||||
For benchmarks where `seq` solves in under 2 s but `nseq` times out (seq-fast/nseq-slow cases), collect a brief `seq` trace to understand what algorithm is used:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
Z3=/tmp/z3-build/z3
|
||||
mkdir -p /tmp/traces
|
||||
|
||||
Z3=${{ github.workspace }}/build/z3
|
||||
ZIPT_DLL=$(find /tmp/zipt/ZIPT/bin/Release -name "ZIPT.dll" 2>/dev/null | head -1)
|
||||
ZIPT_AVAILABLE=false
|
||||
[ -n "$ZIPT_DLL" ] && ZIPT_AVAILABLE=true
|
||||
# Find seq-fast / nseq-slow files: seq solved (sat/unsat) in <2000ms AND nseq timed out
|
||||
awk -F, 'NR>1 && ($2=="sat"||$2=="unsat") && $3<2000 && $4=="timeout" {print $1}' \
|
||||
/tmp/benchmark-results.csv > /tmp/seq_fast_nseq_slow.txt
|
||||
echo "seq-fast / nseq-slow files: $(wc -l < /tmp/seq_fast_nseq_slow.txt)"
|
||||
|
||||
# Ensure libz3.so is on the dynamic-linker path for the .NET runtime
|
||||
export LD_LIBRARY_PATH=${{ github.workspace }}/build${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
|
||||
|
||||
RESULTS=/tmp/benchmark_results.tsv
|
||||
TRACES_DIR=/tmp/seq_traces
|
||||
mkdir -p "$TRACES_DIR"
|
||||
|
||||
echo -e "file\tseq_verdict\tseq_time\tnseq_verdict\tnseq_time\tzipt_verdict\tzipt_time\tnotes" > "$RESULTS"
|
||||
|
||||
run_z3_seq_traced() {
|
||||
# Run seq solver with -tr:seq tracing. Cap at 5 s so trace files stay manageable.
|
||||
local file="$1"
|
||||
local trace_dest="$2"
|
||||
local start end elapsed verdict output exit_code
|
||||
|
||||
# Remove any leftover trace from a prior run so we can detect whether one was produced.
|
||||
rm -f .z3-trace
|
||||
|
||||
start=$(date +%s%3N)
|
||||
output=$(timeout 7 "$Z3" "smt.string_solver=seq" -tr:seq -T:5 "$file" 2>&1)
|
||||
exit_code=$?
|
||||
end=$(date +%s%3N)
|
||||
elapsed=$(echo "scale=3; ($end - $start) / 1000" | bc)
|
||||
|
||||
# Rename the trace file immediately so the next run does not overwrite it.
|
||||
if [ -f .z3-trace ]; then
|
||||
mv .z3-trace "$trace_dest"
|
||||
else
|
||||
# Write a sentinel so Phase 4 can detect the absence of a trace.
|
||||
echo "(no trace produced)" > "$trace_dest"
|
||||
fi
|
||||
|
||||
if echo "$output" | grep -q "^unsat"; then
|
||||
verdict="unsat"
|
||||
elif echo "$output" | grep -q "^sat"; then
|
||||
verdict="sat"
|
||||
elif echo "$output" | grep -q "^unknown"; then
|
||||
verdict="unknown"
|
||||
elif [ "$exit_code" -eq 124 ]; then
|
||||
verdict="timeout"
|
||||
elif echo "$output" | grep -qi "error\|assertion\|segfault\|SIGABRT\|exception"; then
|
||||
verdict="bug"
|
||||
else
|
||||
verdict="unknown"
|
||||
fi
|
||||
|
||||
echo "$verdict $elapsed"
|
||||
}
|
||||
|
||||
run_z3_nseq() {
|
||||
local file="$1"
|
||||
local start end elapsed verdict output exit_code
|
||||
|
||||
start=$(date +%s%3N)
|
||||
output=$(timeout 12 "$Z3" "smt.string_solver=nseq" -T:5 "$file" 2>&1)
|
||||
exit_code=$?
|
||||
end=$(date +%s%3N)
|
||||
elapsed=$(echo "scale=3; ($end - $start) / 1000" | bc)
|
||||
|
||||
if echo "$output" | grep -q "^unsat"; then
|
||||
verdict="unsat"
|
||||
elif echo "$output" | grep -q "^sat"; then
|
||||
verdict="sat"
|
||||
elif echo "$output" | grep -q "^unknown"; then
|
||||
verdict="unknown"
|
||||
elif [ "$exit_code" -eq 124 ]; then
|
||||
verdict="timeout"
|
||||
elif echo "$output" | grep -qi "error\|assertion\|segfault\|SIGABRT\|exception"; then
|
||||
verdict="bug"
|
||||
else
|
||||
verdict="unknown"
|
||||
fi
|
||||
|
||||
echo "$verdict $elapsed"
|
||||
}
|
||||
|
||||
run_zipt() {
|
||||
local file="$1"
|
||||
local start end elapsed verdict output exit_code
|
||||
|
||||
if [ "$ZIPT_AVAILABLE" != "true" ]; then
|
||||
echo "n/a 0.000"
|
||||
return
|
||||
fi
|
||||
|
||||
start=$(date +%s%3N)
|
||||
# ZIPT prints the filename on the first line, then SAT/UNSAT/UNKNOWN on subsequent lines
|
||||
output=$(timeout 12 dotnet "$ZIPT_DLL" -t:5000 "$file" 2>&1)
|
||||
exit_code=$?
|
||||
end=$(date +%s%3N)
|
||||
elapsed=$(echo "scale=3; ($end - $start) / 1000" | bc)
|
||||
|
||||
if echo "$output" | grep -qi "^UNSAT$"; then
|
||||
verdict="unsat"
|
||||
elif echo "$output" | grep -qi "^SAT$"; then
|
||||
verdict="sat"
|
||||
elif echo "$output" | grep -qi "^UNKNOWN$"; then
|
||||
verdict="unknown"
|
||||
elif [ "$exit_code" -eq 124 ]; then
|
||||
verdict="timeout"
|
||||
elif echo "$output" | grep -qi "error\|crash\|exception\|Unsupported"; then
|
||||
verdict="bug"
|
||||
else
|
||||
verdict="unknown"
|
||||
fi
|
||||
|
||||
echo "$verdict $elapsed"
|
||||
}
|
||||
|
||||
while IFS= read -r file; do
|
||||
fname=$(basename "$file")
|
||||
# Use a sanitised filename (replace non-alphanumeric with _) for the trace path.
|
||||
safe_name=$(echo "$fname" | tr -cs 'A-Za-z0-9._-' '_')
|
||||
trace_path="$TRACES_DIR/${safe_name}.z3-trace"
|
||||
|
||||
seq_result=$(run_z3_seq_traced "$file" "$trace_path")
|
||||
nseq_result=$(run_z3_nseq "$file")
|
||||
zipt_result=$(run_zipt "$file")
|
||||
|
||||
seq_verdict=$(echo "$seq_result" | cut -d' ' -f1)
|
||||
seq_time=$(echo "$seq_result" | cut -d' ' -f2)
|
||||
nseq_verdict=$(echo "$nseq_result" | cut -d' ' -f1)
|
||||
nseq_time=$(echo "$nseq_result" | cut -d' ' -f2)
|
||||
zipt_verdict=$(echo "$zipt_result" | cut -d' ' -f1)
|
||||
zipt_time=$(echo "$zipt_result" | cut -d' ' -f2)
|
||||
|
||||
# Flag soundness disagreement when any two definitive verdicts disagree
|
||||
notes=""
|
||||
# Build list of (solver, verdict) pairs for definitive answers only
|
||||
declare -A definitive_map
|
||||
[ "$seq_verdict" = "sat" ] || [ "$seq_verdict" = "unsat" ] && definitive_map[seq]="$seq_verdict"
|
||||
[ "$nseq_verdict" = "sat" ] || [ "$nseq_verdict" = "unsat" ] && definitive_map[nseq]="$nseq_verdict"
|
||||
[ "$zipt_verdict" = "sat" ] || [ "$zipt_verdict" = "unsat" ] && definitive_map[zipt]="$zipt_verdict"
|
||||
# Check every pair for conflict
|
||||
has_sat=false; has_unsat=false
|
||||
for v in "${definitive_map[@]}"; do
|
||||
[ "$v" = "sat" ] && has_sat=true
|
||||
[ "$v" = "unsat" ] && has_unsat=true
|
||||
done
|
||||
if $has_sat && $has_unsat; then
|
||||
notes="SOUNDNESS_DISAGREEMENT"
|
||||
fi
|
||||
|
||||
echo -e "$fname\t$seq_verdict\t$seq_time\t$nseq_verdict\t$nseq_time\t$zipt_verdict\t$zipt_time\t$notes" >> "$RESULTS"
|
||||
echo "[$fname] seq=$seq_verdict(${seq_time}s) nseq=$nseq_verdict(${nseq_time}s) zipt=$zipt_verdict(${zipt_time}s) $notes"
|
||||
done < /tmp/selected_files.txt
|
||||
|
||||
echo "Benchmark run complete. Results saved to $RESULTS"
|
||||
echo "Trace files saved to $TRACES_DIR"
|
||||
```
|
||||
|
||||
Save this script to `/tmp/run_benchmarks.sh`, make it executable, and run it.
|
||||
|
||||
## Phase 3.5: Identify seq-fast / nseq-slow Cases and Analyse Traces
|
||||
|
||||
After the benchmark loop completes, identify files where seq solved the instance quickly but nseq was significantly slower (or timed out). For each such file, read its saved seq trace and produce a hypothesis for why nseq is slower.
|
||||
|
||||
**Definition of "seq-fast / nseq-slow"**: seq_time < 1.0 s AND nseq_time > 3 × seq_time (and nseq_time > 0.5 s).
|
||||
|
||||
For each matching file:
|
||||
1. Read the corresponding trace file from `/tmp/seq_traces/`.
|
||||
2. Look for the sequence of lemmas, reductions, or decisions that led seq to a fast conclusion.
|
||||
3. Identify patterns absent or less exploited in nseq: e.g., length-based propagation early in the trace, Parikh constraints eliminating possibilities, Nielsen graph pruning, equation splitting, or overlap resolution.
|
||||
4. Write a 3–5 sentence hypothesis explaining the likely reason for the nseq slowdown, referencing specific trace entries where possible.
|
||||
|
||||
Use a script to collect the candidates:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
RESULTS=/tmp/benchmark_results.tsv
|
||||
TRACES_DIR=/tmp/seq_traces
|
||||
ANALYSIS=/tmp/trace_analysis.md
|
||||
|
||||
echo "# Trace Analysis: seq-fast / nseq-slow Candidates" > "$ANALYSIS"
|
||||
echo "" >> "$ANALYSIS"
|
||||
|
||||
# Skip header line; columns: file seq_verdict seq_time nseq_verdict nseq_time ...
|
||||
tail -n +2 "$RESULTS" | while IFS=$'\t' read -r fname seq_verdict seq_time nseq_verdict nseq_time _rest; do
|
||||
# Use bc for floating-point comparison; bc does not support && so split into separate tests.
|
||||
is_fast=$(echo "$seq_time < 1.0" | bc -l 2>/dev/null || echo 0)
|
||||
threshold=$(echo "$seq_time * 3" | bc -l 2>/dev/null || echo 99999)
|
||||
is_slow_threshold=$(echo "$nseq_time > $threshold" | bc -l 2>/dev/null || echo 0)
|
||||
# Extra guard: exclude trivially fast seq cases where 3× is still < 0.5 s
|
||||
is_over_half=$(echo "$nseq_time > 0.5" | bc -l 2>/dev/null || echo 0)
|
||||
|
||||
if [ "$is_fast" = "1" ] && [ "$is_slow_threshold" = "1" ] && [ "$is_over_half" = "1" ]; then
|
||||
safe_name=$(echo "$fname" | tr -cs 'A-Za-z0-9._-' '_')
|
||||
trace_path="$TRACES_DIR/${safe_name}.z3-trace"
|
||||
echo "## $fname" >> "$ANALYSIS"
|
||||
echo "" >> "$ANALYSIS"
|
||||
echo "seq: ${seq_time}s (${seq_verdict}), nseq: ${nseq_time}s (${nseq_verdict})" >> "$ANALYSIS"
|
||||
echo "" >> "$ANALYSIS"
|
||||
echo "### Trace excerpt (first 200 lines)" >> "$ANALYSIS"
|
||||
echo '```' >> "$ANALYSIS"
|
||||
head -200 "$trace_path" 2>/dev/null >> "$ANALYSIS" || echo "(trace file not found on disk)" >> "$ANALYSIS"
|
||||
echo '```' >> "$ANALYSIS"
|
||||
echo "" >> "$ANALYSIS"
|
||||
echo "---" >> "$ANALYSIS"
|
||||
echo "" >> "$ANALYSIS"
|
||||
fi
|
||||
# Collect traces for at most 5 such cases
|
||||
head -5 /tmp/seq_fast_nseq_slow.txt | while IFS= read -r short; do
|
||||
# Find the full path
|
||||
full=$(grep "/$short$" /tmp/qf_s_sample.txt | head -1)
|
||||
[ -z "$full" ] && continue
|
||||
timeout 5 "$Z3" \
|
||||
smt.string_solver=seq \
|
||||
-tr:seq \
|
||||
-T:5 \
|
||||
"$full" > "/tmp/traces/${short%.smt2}.seq.trace" 2>&1 || true
|
||||
done
|
||||
|
||||
echo "Candidate list written to $ANALYSIS"
|
||||
cat "$ANALYSIS"
|
||||
```
|
||||
|
||||
Save this to `/tmp/analyse_traces.sh`, make it executable, and run it. Then read the trace excerpts collected in `/tmp/trace_analysis.md` and — for each candidate — write your hypothesis in the Phase 4 summary report under a **"Trace Analysis"** section.
|
||||
## Phase 6: Analyze Results
|
||||
|
||||
## Phase 4: Generate Summary Report
|
||||
Compute summary statistics from the CSV. Save the analysis script to a file and run it:
|
||||
|
||||
Read `/tmp/benchmark_results.tsv` and compute statistics. Then generate a Markdown report.
|
||||
```bash
|
||||
cat > /tmp/analyze_benchmark.py << 'PYEOF'
|
||||
import csv, sys
|
||||
|
||||
Compute:
|
||||
- **Total benchmarks**: 200
|
||||
- **Per solver (seq, nseq, and ZIPT)**: count of sat / unsat / unknown / timeout / bug verdicts
|
||||
- **Total time used**: sum of all times for each solver
|
||||
- **Average time per benchmark**: total_time / 200
|
||||
- **Soundness disagreements**: files where any two solvers that both returned a definitive answer disagree (these are the most critical bugs)
|
||||
- **Bugs / crashes**: files with error/crash verdicts
|
||||
results = []
|
||||
with open('/tmp/benchmark-results.csv') as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
results.append(row)
|
||||
|
||||
Format the report as a GitHub Discussion post (GitHub-flavored Markdown):
|
||||
total = len(results)
|
||||
if total == 0:
|
||||
print("No results found.")
|
||||
sys.exit(0)
|
||||
|
||||
def is_correct(r, solver):
|
||||
prefix = 'seq' if solver == 'seq' else 'nseq'
|
||||
return r[f'{prefix}_result'] in ('sat', 'unsat')
|
||||
|
||||
def timed_out(r, solver):
|
||||
prefix = 'seq' if solver == 'seq' else 'nseq'
|
||||
return r[f'{prefix}_result'] == 'timeout'
|
||||
|
||||
seq_solved = sum(1 for r in results if is_correct(r, 'seq'))
|
||||
nseq_solved = sum(1 for r in results if is_correct(r, 'nseq'))
|
||||
seq_to = sum(1 for r in results if timed_out(r, 'seq'))
|
||||
nseq_to = sum(1 for r in results if timed_out(r, 'nseq'))
|
||||
|
||||
seq_times = [int(r['seq_time_ms']) for r in results if is_correct(r, 'seq')]
|
||||
nseq_times = [int(r['nseq_time_ms']) for r in results if is_correct(r, 'nseq')]
|
||||
|
||||
def median(lst):
|
||||
s = sorted(lst)
|
||||
n = len(s)
|
||||
return s[n//2] if n else 0
|
||||
|
||||
def mean(lst):
|
||||
return sum(lst)//len(lst) if lst else 0
|
||||
|
||||
# Disagreements (sat vs unsat or vice-versa)
|
||||
disagreements = [
|
||||
r for r in results
|
||||
if r['seq_result'] in ('sat','unsat')
|
||||
and r['nseq_result'] in ('sat','unsat')
|
||||
and r['seq_result'] != r['nseq_result']
|
||||
]
|
||||
|
||||
# seq-fast / nseq-slow: seq solved in <2s, nseq timed out
|
||||
seq_fast_nseq_slow = [
|
||||
r for r in results
|
||||
if is_correct(r, 'seq') and int(r['seq_time_ms']) < 2000 and timed_out(r, 'nseq')
|
||||
]
|
||||
# nseq-fast / seq-slow: nseq solved in <2s, seq timed out
|
||||
nseq_fast_seq_slow = [
|
||||
r for r in results
|
||||
if is_correct(r, 'nseq') and int(r['nseq_time_ms']) < 2000 and timed_out(r, 'seq')
|
||||
]
|
||||
|
||||
print(f"TOTAL={total}")
|
||||
print(f"SEQ_SOLVED={seq_solved}")
|
||||
print(f"NSEQ_SOLVED={nseq_solved}")
|
||||
print(f"SEQ_TIMEOUTS={seq_to}")
|
||||
print(f"NSEQ_TIMEOUTS={nseq_to}")
|
||||
print(f"SEQ_MEDIAN_MS={median(seq_times)}")
|
||||
print(f"NSEQ_MEDIAN_MS={median(nseq_times)}")
|
||||
print(f"SEQ_MEAN_MS={mean(seq_times)}")
|
||||
print(f"NSEQ_MEAN_MS={mean(nseq_times)}")
|
||||
print(f"DISAGREEMENTS={len(disagreements)}")
|
||||
print(f"SEQ_FAST_NSEQ_SLOW={len(seq_fast_nseq_slow)}")
|
||||
print(f"NSEQ_FAST_SEQ_SLOW={len(nseq_fast_seq_slow)}")
|
||||
|
||||
# Print top-10 slowest for nseq that seq handles fast
|
||||
print("\nTOP_SEQ_FAST_NSEQ_SLOW:")
|
||||
for r in sorted(seq_fast_nseq_slow, key=lambda x: -int(x['nseq_time_ms']))[:10]:
|
||||
print(f" {r['file']} seq={r['seq_time_ms']}ms nseq={r['nseq_time_ms']}ms seq_result={r['seq_result']} nseq_result={r['nseq_result']}")
|
||||
|
||||
print("\nTOP_NSEQ_FAST_SEQ_SLOW:")
|
||||
for r in sorted(nseq_fast_seq_slow, key=lambda x: -int(x['seq_time_ms']))[:10]:
|
||||
print(f" {r['file']} seq={r['seq_time_ms']}ms nseq={r['nseq_time_ms']}ms seq_result={r['seq_result']} nseq_result={r['nseq_result']}")
|
||||
|
||||
if disagreements:
|
||||
print(f"\nDISAGREEMENTS ({len(disagreements)}):")
|
||||
for r in disagreements[:10]:
|
||||
print(f" {r['file']} seq={r['seq_result']} nseq={r['nseq_result']}")
|
||||
PYEOF
|
||||
|
||||
python3 /tmp/analyze_benchmark.py
|
||||
```
|
||||
|
||||
## Phase 7: Create GitHub Discussion
|
||||
|
||||
Use the `create_discussion` safe-output tool to post a structured benchmark report.
|
||||
|
||||
The discussion body should be formatted as follows (fill in real numbers from Phase 6):
|
||||
|
||||
```markdown
|
||||
### ZIPT Benchmark Report — Z3 c3 branch
|
||||
# QF_S Benchmark: seq vs nseq
|
||||
|
||||
**Date**: <today's date>
|
||||
**Date**: YYYY-MM-DD
|
||||
**Branch**: c3
|
||||
**Benchmark set**: QF_S (200 randomly selected files from tests/QF_S.tar.zst)
|
||||
**Timeout**: 5 seconds for seq (`-T:5`); 5 seconds for nseq (`-T:5`) and ZIPT (`-t:5000`)
|
||||
**Commit**: `<short SHA>`
|
||||
**Workflow Run**: [#<run_id>](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
||||
**Files benchmarked**: N (capped at 300, timeout 5 s per file)
|
||||
|
||||
---
|
||||
|
||||
### Summary
|
||||
## Summary
|
||||
|
||||
| Metric | seq solver | nseq solver | ZIPT solver |
|
||||
|--------|-----------|-------------|-------------|
|
||||
| sat | X | X | X |
|
||||
| unsat | X | X | X |
|
||||
| unknown | X | X | X |
|
||||
| timeout | X | X | X |
|
||||
| bug/crash | X | X | X |
|
||||
| **Total time (s)** | X.XXX | X.XXX | X.XXX |
|
||||
| **Avg time/benchmark (s)** | X.XXX | X.XXX | X.XXX |
|
||||
|
||||
**Soundness disagreements** (any two solvers return conflicting sat/unsat): N
|
||||
| Metric | seq | nseq |
|
||||
|--------|-----|------|
|
||||
| Files solved (sat/unsat) | SEQ_SOLVED | NSEQ_SOLVED |
|
||||
| Timeouts | SEQ_TO | NSEQ_TO |
|
||||
| Median solve time (solved files) | X ms | Y ms |
|
||||
| Mean solve time (solved files) | X ms | Y ms |
|
||||
| **Disagreements (sat≠unsat)** | — | N |
|
||||
|
||||
---
|
||||
|
||||
### Per-File Results
|
||||
## Performance Comparison
|
||||
|
||||
| # | File | seq verdict | seq time (s) | nseq verdict | nseq time (s) | ZIPT verdict | ZIPT time (s) | Notes |
|
||||
|---|------|-------------|-------------|--------------|--------------|--------------|--------------|-------|
|
||||
| 1 | benchmark_0001.smt2 | sat | 0.123 | sat | 0.456 | sat | 0.789 | |
|
||||
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
|
||||
### seq-fast / nseq-slow (seq < 2 s, nseq timed out)
|
||||
|
||||
These are benchmarks where the classical `seq` solver is significantly faster. These represent regression risk for `nseq`.
|
||||
|
||||
| File | seq (ms) | nseq (ms) | seq result | nseq result |
|
||||
|------|----------|-----------|------------|-------------|
|
||||
[TOP 10 ENTRIES]
|
||||
|
||||
### nseq-fast / seq-slow (nseq < 2 s, seq timed out)
|
||||
|
||||
These are benchmarks where `nseq` shows a performance advantage.
|
||||
|
||||
| File | seq (ms) | nseq (ms) | seq result | nseq result |
|
||||
|------|----------|-----------|------------|-------------|
|
||||
[TOP 10 ENTRIES]
|
||||
|
||||
---
|
||||
|
||||
### Notable Issues
|
||||
## Correctness
|
||||
|
||||
#### Soundness Disagreements (Critical)
|
||||
<list files where any two solvers disagree on sat/unsat, naming which solvers disagree>
|
||||
**Disagreements** (files where seq says `sat` but nseq says `unsat` or vice versa): N
|
||||
|
||||
#### Crashes / Bugs
|
||||
<list files where any solver crashed or produced an error>
|
||||
|
||||
#### Slow Benchmarks (> 8s)
|
||||
<list files that took more than 8 seconds for any solver>
|
||||
|
||||
#### Trace Analysis: seq-fast / nseq-slow Hypotheses
|
||||
<For each file where seq finished in < 1 s and nseq took > 3× longer, write a 3–5 sentence hypothesis based on the trace excerpt, referencing specific trace entries where possible. If no such files were found, state "No seq-fast / nseq-slow cases were observed in this run.">
|
||||
[If disagreements exist, list all of them here with file paths and both results]
|
||||
|
||||
---
|
||||
|
||||
*Generated automatically by the ZIPT Benchmark workflow on the c3 branch.*
|
||||
## seq Trace Analysis (seq-fast / nseq-slow cases)
|
||||
|
||||
<details>
|
||||
<summary>Click to expand trace snippets for top seq-fast/nseq-slow cases</summary>
|
||||
|
||||
[Insert trace snippet for each traced file, or "No traces collected" if section was skipped]
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Raw Data
|
||||
|
||||
<details>
|
||||
<summary>Full results CSV (click to expand)</summary>
|
||||
|
||||
```csv
|
||||
[PASTE FIRST 200 LINES OF /tmp/benchmark-results.csv]
|
||||
```
|
||||
|
||||
## Phase 5: Post to GitHub Discussion
|
||||
</details>
|
||||
|
||||
Post the Markdown report as a new GitHub Discussion using the `create-discussion` safe output.
|
||||
---
|
||||
|
||||
- **Category**: "Agentic Workflows"
|
||||
- **Title**: `[ZIPT Benchmark] Z3 c3 branch — <date>`
|
||||
- Close older discussions with the same title prefix to avoid clutter.
|
||||
*Generated by the QF_S Benchmark workflow. To reproduce: build Z3 from the `c3` branch and run `z3 smt.string_solver=seq|nseq -T:10 <file.smt2>`.*
|
||||
```
|
||||
|
||||
## Guidelines
|
||||
## Edge Cases
|
||||
|
||||
- **Always build from c3 branch**: The workspace is already checked out on c3; don't change branches.
|
||||
- **Debug build required**: The build must use `CMAKE_BUILD_TYPE=Debug` so that Z3's internal assertions and trace infrastructure are active; `-tr:` trace flags have no effect in Release builds.
|
||||
- **Tracing time cap**: Always pass `-T:5` when running with `-tr:seq` to limit solver runtime and keep trace files a manageable size. The nseq and ZIPT runs use `-T:5` / `-t:5000` as before.
|
||||
- **Rename trace files immediately**: After each seq run, rename `.z3-trace` to a per-benchmark path before starting the next run, or the next invocation will overwrite it.
|
||||
- **Handle build failures gracefully**: If Z3 fails to build, report the error and create a brief discussion noting the build failure. If ZIPT fails to build, continue with only the seq/nseq columns and note `n/a` for ZIPT results.
|
||||
- **Handle missing zstd**: If `tar --zstd` fails, try `zstd -d tests/QF_S.tar.zst --stdout | tar -x -C /tmp/qfs_benchmarks`.
|
||||
- **Be precise with timing**: Use millisecond-precision timestamps and report times in seconds with 3 decimal places.
|
||||
- **Distinguish timeout from unknown**: A timeout (process killed after 7s outer / 5s Z3-internal for seq, or 12s/10s for nseq) is different from `(unknown)` returned by a solver.
|
||||
- **ZIPT timeout unit**: ZIPT's `-t` flag takes **milliseconds**, so pass `-t:5000` for a 5-second limit.
|
||||
- **ZIPT output format**: ZIPT prints the input filename on the first line, then `SAT`, `UNSAT`, or `UNKNOWN` on subsequent lines. Parse accordingly.
|
||||
- **Report soundness bugs prominently**: If any benchmark shows a conflict between any two solvers that both returned a definitive sat/unsat answer, highlight it as a critical finding and name which pair disagrees.
|
||||
- **Don't skip any file**: Run all 200 files even if some fail.
|
||||
- **Large report**: If the per-file table is very long, put it in a `<details>` collapsible section.
|
||||
- If the build fails, call `missing_data` explaining the build error and stop.
|
||||
- If no benchmark files are found at all, call `missing_data` explaining that no QF_S `.smt2` files were found in the `c3` branch.
|
||||
- If Z3 crashes (segfault) on a file with either solver, record the result as `crash` and continue.
|
||||
- If the total benchmark set is very small (< 5 files), note this prominently in the discussion and suggest adding more QF_S benchmarks to the `c3` branch.
|
||||
- If zero disagreements and both solvers time out on the same files, note that the solvers are in agreement.
|
||||
- If `create_discussion` fails (e.g., MCP session error), call `report_incomplete` with the reason and include the top-line statistics (files solved, timeouts, disagreement count) in the `details` field.
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **DO NOT** modify any source files or create pull requests.
|
||||
- **DO NOT** run `ninja` or any build command in the background with `&` — concurrent C++ compilation and LLM inference can exhaust available RAM and kill the agent process. Always wait for build commands to complete before proceeding.
|
||||
- **DO NOT** run benchmarks for longer than 100 minutes total (leave buffer for posting).
|
||||
- **DO** always report the commit SHA so results can be correlated with specific code versions.
|
||||
- **DO** close older QF_S Benchmark discussions automatically (configured via `close-older-discussions: true`).
|
||||
- **DO** highlight disagreements prominently — these are potential correctness bugs.
|
||||
|
|
|
|||
2
.github/workflows/release-notes-updater.md
vendored
2
.github/workflows/release-notes-updater.md
vendored
|
|
@ -16,8 +16,6 @@ tools:
|
|||
toolsets: [default]
|
||||
bash: [":*"]
|
||||
edit: {}
|
||||
glob: {}
|
||||
view: {}
|
||||
|
||||
safe-outputs:
|
||||
create-discussion:
|
||||
|
|
|
|||
222
.github/workflows/release.yml
vendored
222
.github/workflows/release.yml
vendored
|
|
@ -46,6 +46,19 @@ jobs:
|
|||
- name: Build
|
||||
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=x64
|
||||
|
||||
- name: Validate libz3.dylib and z3 architecture (must be x86_64)
|
||||
run: |
|
||||
set -e
|
||||
for f in build-dist/libz3.dylib build-dist/z3; do
|
||||
ARCH=$(lipo -archs "$f")
|
||||
echo "$f architecture: $ARCH"
|
||||
if [ "$ARCH" != "x86_64" ]; then
|
||||
echo "ERROR: $f has arch '$ARCH', expected 'x86_64' (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "OK: macOS x64 artifacts are x86_64"
|
||||
|
||||
- name: Clone z3test
|
||||
run: git clone https://github.com/z3prover/z3test z3test
|
||||
|
||||
|
|
@ -53,7 +66,7 @@ jobs:
|
|||
run: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: macOsBuild
|
||||
path: dist/*.zip
|
||||
|
|
@ -75,11 +88,24 @@ jobs:
|
|||
- name: Build
|
||||
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64
|
||||
|
||||
- name: Validate libz3.dylib and z3 architecture (must be arm64)
|
||||
run: |
|
||||
set -e
|
||||
for f in build-dist/libz3.dylib build-dist/z3; do
|
||||
ARCH=$(lipo -archs "$f")
|
||||
echo "$f architecture: $ARCH"
|
||||
if [ "$ARCH" != "arm64" ]; then
|
||||
echo "ERROR: $f has arch '$ARCH', expected 'arm64' (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "OK: macOS arm64 artifacts are arm64"
|
||||
|
||||
- name: Clone z3test
|
||||
run: git clone https://github.com/z3prover/z3test z3test
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: MacArm64
|
||||
path: dist/*.zip
|
||||
|
|
@ -111,6 +137,17 @@ jobs:
|
|||
Z3_DIR=$(find . -maxdepth 1 -type d -name "z3-*" | head -n 1)
|
||||
echo "Z3_DIR=$Z3_DIR" >> $GITHUB_ENV
|
||||
|
||||
- name: Validate shipped libz3.dylib architecture (must be x86_64)
|
||||
run: |
|
||||
set -e
|
||||
DYLIB="artifacts/$Z3_DIR/bin/libz3.dylib"
|
||||
ARCH=$(lipo -archs "$DYLIB")
|
||||
echo "Shipped $DYLIB architecture: $ARCH"
|
||||
if [ "$ARCH" != "x86_64" ]; then
|
||||
echo "ERROR: x64 release zip contains '$ARCH' libz3.dylib (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Test install_name_tool with headerpad
|
||||
run: |
|
||||
cd artifacts/$Z3_DIR/bin
|
||||
|
|
@ -159,6 +196,17 @@ jobs:
|
|||
Z3_DIR=$(find . -maxdepth 1 -type d -name "z3-*" | head -n 1)
|
||||
echo "Z3_DIR=$Z3_DIR" >> $GITHUB_ENV
|
||||
|
||||
- name: Validate shipped libz3.dylib architecture (must be arm64)
|
||||
run: |
|
||||
set -e
|
||||
DYLIB="artifacts/$Z3_DIR/bin/libz3.dylib"
|
||||
ARCH=$(lipo -archs "$DYLIB")
|
||||
echo "Shipped $DYLIB architecture: $ARCH"
|
||||
if [ "$ARCH" != "arm64" ]; then
|
||||
echo "ERROR: arm64 release zip contains '$ARCH' libz3.dylib (see issue #9662)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Test install_name_tool with headerpad
|
||||
run: |
|
||||
cd artifacts/$Z3_DIR/bin
|
||||
|
|
@ -208,7 +256,7 @@ jobs:
|
|||
run: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: UbuntuBuild
|
||||
path: dist/*.zip
|
||||
|
|
@ -243,7 +291,7 @@ jobs:
|
|||
python scripts/mk_unix_dist.py --nodotnet --arch=arm64
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: UbuntuArm64
|
||||
path: dist/*.zip
|
||||
|
|
@ -298,7 +346,7 @@ jobs:
|
|||
run: zip -r z3doc.zip doc/api
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: UbuntuDoc
|
||||
path: z3doc.zip
|
||||
|
|
@ -313,9 +361,17 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python environment
|
||||
run: |
|
||||
/opt/python/cp38-cp38/bin/python -m venv $PWD/env
|
||||
"$PYTHON" -m venv $PWD/env
|
||||
echo "$PWD/env/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install build tools
|
||||
|
|
@ -328,7 +384,7 @@ jobs:
|
|||
run: pip install ./src/api/python/wheelhouse/*.whl && python - <src/api/python/z3test.py z3 && python - <src/api/python/z3test.py z3num
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildAMD64
|
||||
path: src/api/python/wheelhouse/*.whl
|
||||
|
|
@ -351,9 +407,17 @@ jobs:
|
|||
mkdir -p /tmp/arm-toolchain/
|
||||
tar xf /tmp/arm-toolchain.tar.xz -C /tmp/arm-toolchain/ --strip-components=1
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python environment
|
||||
run: |
|
||||
/opt/python/cp38-cp38/bin/python -m venv $PWD/env
|
||||
"$PYTHON" -m venv $PWD/env
|
||||
echo "$PWD/env/bin" >> $GITHUB_PATH
|
||||
echo "/tmp/arm-toolchain/bin" >> $GITHUB_PATH
|
||||
echo "/tmp/arm-toolchain/aarch64-none-linux-gnu/libc/usr/bin" >> $GITHUB_PATH
|
||||
|
|
@ -368,12 +432,120 @@ jobs:
|
|||
run: cd src/api/python && CC=aarch64-none-linux-gnu-gcc CXX=aarch64-none-linux-gnu-g++ AR=aarch64-none-linux-gnu-ar LD=aarch64-none-linux-gnu-ld Z3_CROSS_COMPILING=aarch64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildArm64
|
||||
path: src/api/python/wheelhouse/*.whl
|
||||
retention-days: 7
|
||||
|
||||
manylinux-python-riscv64:
|
||||
name: "Python bindings (manylinux RISC-V 64 cross)"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
container: quay.io/pypa/manylinux_2_28_x86_64:latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Download RISC-V toolchain
|
||||
run: curl -L -o /tmp/riscv-toolchain.tar.gz 'https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2024.09.03/riscv64-glibc-ubuntu-20.04-gcc-nightly-2024.09.03-nightly.tar.gz'
|
||||
|
||||
- name: Extract RISC-V toolchain
|
||||
run: |
|
||||
mkdir -p /tmp/riscv-toolchain/
|
||||
tar xf /tmp/riscv-toolchain.tar.gz -C /tmp/riscv-toolchain/ --strip-components=1
|
||||
|
||||
- name: Install MPFR 4 (required by RISC-V toolchain host binaries)
|
||||
run: |
|
||||
dnf install -y gmp-devel
|
||||
curl -L -o /tmp/mpfr.tar.xz https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.1.tar.xz
|
||||
tar xf /tmp/mpfr.tar.xz -C /tmp/
|
||||
cd /tmp/mpfr-4.2.1 && ./configure --prefix=/usr/local --disable-static && make -j$(nproc) && make install
|
||||
ldconfig
|
||||
|
||||
- name: Select Python
|
||||
run: |
|
||||
# Use the first available manylinux interpreter for deterministic selection.
|
||||
PYTHON=$(printf '%s\n' /opt/python/*/bin/python | sort -V | head -n1)
|
||||
test -x "$PYTHON" || { echo "Error: no interpreter found under /opt/python/*/bin/python"; exit 1; }
|
||||
echo "PYTHON=$PYTHON" >> "$GITHUB_ENV"
|
||||
"$PYTHON" --version
|
||||
|
||||
- name: Setup Python environment
|
||||
run: |
|
||||
"$PYTHON" -m venv $PWD/env
|
||||
echo "$PWD/env/bin" >> $GITHUB_PATH
|
||||
echo "/tmp/riscv-toolchain/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install build tools
|
||||
run: |
|
||||
echo $PATH
|
||||
stat $(which riscv64-unknown-linux-gnu-gcc)
|
||||
pip install build git+https://github.com/rhelmot/auditwheel
|
||||
|
||||
- name: Build wheels
|
||||
run: cd src/api/python && CC=riscv64-unknown-linux-gnu-gcc CXX=riscv64-unknown-linux-gnu-g++ AR=riscv64-unknown-linux-gnu-ar LD=riscv64-unknown-linux-gnu-ld Z3_CROSS_COMPILING=riscv64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildRiscv64
|
||||
path: src/api/python/wheelhouse/*.whl
|
||||
retention-days: 7
|
||||
|
||||
pyodide-python:
|
||||
name: "Python bindings (Pyodide)"
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6.0.2
|
||||
|
||||
- name: Setup packages
|
||||
run: sudo apt-get update && sudo apt-get install -y python3-dev python3-pip python3-venv
|
||||
|
||||
- name: Create venv
|
||||
run: python3 -m venv ~/env
|
||||
|
||||
- name: Install pyodide
|
||||
run: ~/env/bin/pip install pyodide-build pyodide-cli
|
||||
|
||||
- name: Configure Emscripten
|
||||
run: |
|
||||
git clone https://github.com/emscripten-core/emsdk.git ~/emsdk
|
||||
cd ~/emsdk
|
||||
PYODIDE_EMSCRIPTEN_VERSION=$(~/env/bin/pyodide config get emscripten_version)
|
||||
./emsdk install ${PYODIDE_EMSCRIPTEN_VERSION}
|
||||
./emsdk activate ${PYODIDE_EMSCRIPTEN_VERSION}
|
||||
|
||||
- name: Build wheel
|
||||
run: |
|
||||
source ~/emsdk/emsdk_env.sh
|
||||
cd src/api/python
|
||||
CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" CXXFLAGS="${CXXFLAGS}" ~/env/bin/pyodide build --exports whole_archive
|
||||
env:
|
||||
CFLAGS: "-fexceptions -s DISABLE_EXCEPTION_CATCHING=0 -g2"
|
||||
LDFLAGS: "-fexceptions -s WASM_BIGINT"
|
||||
CXXFLAGS: "-fexceptions -s DISABLE_EXCEPTION_CATCHING=0"
|
||||
|
||||
- name: Setup env-pyodide
|
||||
run: |
|
||||
source ~/env/bin/activate
|
||||
source ~/emsdk/emsdk_env.sh
|
||||
pyodide venv ~/env-pyodide
|
||||
|
||||
- name: Test wheel
|
||||
run: |
|
||||
~/env-pyodide/bin/pip install src/api/python/dist/*.whl
|
||||
~/env-pyodide/bin/python src/api/python/z3test.py z3
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: PyodidePythonBuild
|
||||
path: src/api/python/dist/*.whl
|
||||
retention-days: 7
|
||||
|
||||
windows-build-x64:
|
||||
name: "Windows x64 build"
|
||||
runs-on: windows-latest
|
||||
|
|
@ -394,7 +566,7 @@ jobs:
|
|||
python scripts\mk_win_dist.py --x64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: WindowsBuild-x64
|
||||
path: dist/*.zip
|
||||
|
|
@ -420,7 +592,7 @@ jobs:
|
|||
python scripts\mk_win_dist.py --x86-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: WindowsBuild-x86
|
||||
path: dist/*.zip
|
||||
|
|
@ -446,7 +618,7 @@ jobs:
|
|||
python scripts\mk_win_dist_cmake.py --arm64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ env.RELEASE_VERSION }} --zip
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: WindowsBuild-arm64
|
||||
path: dist/arm64/*.zip
|
||||
|
|
@ -506,7 +678,7 @@ jobs:
|
|||
path: package
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@v2
|
||||
uses: nuget/setup-nuget@v4
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
|
|
@ -523,7 +695,7 @@ jobs:
|
|||
nuget pack out\Microsoft.Z3.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: NuGet
|
||||
path: |
|
||||
|
|
@ -551,7 +723,7 @@ jobs:
|
|||
path: package
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@v2
|
||||
uses: nuget/setup-nuget@v4
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
|
|
@ -568,7 +740,7 @@ jobs:
|
|||
nuget pack out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: NuGet32
|
||||
path: |
|
||||
|
|
@ -578,7 +750,7 @@ jobs:
|
|||
|
||||
python-package:
|
||||
name: "Python packaging"
|
||||
needs: [mac-build-x64, mac-build-arm64, windows-build-x64, windows-build-x86, windows-build-arm64, manylinux-python-amd64, manylinux-python-arm64]
|
||||
needs: [mac-build-x64, mac-build-arm64, windows-build-x64, windows-build-x86, windows-build-arm64, manylinux-python-amd64, manylinux-python-arm64, manylinux-python-riscv64, pyodide-python]
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
|
@ -631,6 +803,18 @@ jobs:
|
|||
name: ManyLinuxPythonBuildArm64
|
||||
path: artifacts
|
||||
|
||||
- name: Download ManyLinux RISC-V 64 Build
|
||||
uses: actions/download-artifact@v8.0.1
|
||||
with:
|
||||
name: ManyLinuxPythonBuildRiscv64
|
||||
path: artifacts
|
||||
|
||||
- name: Download Pyodide Build
|
||||
uses: actions/download-artifact@v8.0.1
|
||||
with:
|
||||
name: PyodidePythonBuild
|
||||
path: artifacts
|
||||
|
||||
- name: Extract builds
|
||||
run: |
|
||||
cd artifacts
|
||||
|
|
@ -658,7 +842,7 @@ jobs:
|
|||
cp artifacts/*.whl src/api/python/dist/.
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v7.0.1
|
||||
with:
|
||||
name: PythonPackage
|
||||
path: src/api/python/dist/*
|
||||
|
|
@ -760,7 +944,7 @@ jobs:
|
|||
path: packages
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@v2
|
||||
uses: nuget/setup-nuget@v4
|
||||
with:
|
||||
nuget-version: 'latest'
|
||||
|
||||
|
|
|
|||
1442
.github/workflows/smtlib-benchmark-finder.lock.yml
generated
vendored
Normal file
1442
.github/workflows/smtlib-benchmark-finder.lock.yml
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
342
.github/workflows/smtlib-benchmark-finder.md
vendored
Normal file
342
.github/workflows/smtlib-benchmark-finder.md
vendored
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
---
|
||||
description: >
|
||||
Monthly SMTLIB Benchmark Finder.
|
||||
Searches GitHub for repositories containing SMT-LIB benchmarks (.smt2 files),
|
||||
excludes repositories that belong to the official SMT-LIB benchmark sets
|
||||
(linked from smtlib.org and hosted on Zenodo), and posts a curated summary
|
||||
of community-contributed benchmark links as a GitHub Discussion.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 8 1 * *"
|
||||
workflow_dispatch:
|
||||
|
||||
timeout-minutes: 60
|
||||
|
||||
permissions: read-all
|
||||
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
- github
|
||||
- smtlib.cs.uiowa.edu
|
||||
- zenodo.org
|
||||
|
||||
tools:
|
||||
cache-memory: true
|
||||
web-fetch: {}
|
||||
github:
|
||||
toolsets: [default, repos]
|
||||
bash: [":*"]
|
||||
|
||||
safe-outputs:
|
||||
mentions: false
|
||||
allowed-github-references: []
|
||||
max-bot-mentions: 1
|
||||
create-discussion:
|
||||
title-prefix: "[SMT-LIB Benchmarks] "
|
||||
category: "Agentic Workflows"
|
||||
close-older-discussions: true
|
||||
expires: 90d
|
||||
missing-tool:
|
||||
create-issue: true
|
||||
noop:
|
||||
report-as-issue: false
|
||||
|
||||
---
|
||||
|
||||
# SMTLIB Benchmark Finder
|
||||
|
||||
## Job Description
|
||||
|
||||
Your name is ${{ github.workflow }}. You are a research analyst for the Z3 theorem
|
||||
prover repository `${{ github.repository }}`. Your mission is to discover GitHub
|
||||
repositories that host SMT-LIB benchmarks, exclude the ones that are already part
|
||||
of the official SMT-LIB benchmark distribution (linked from smtlib.org and published
|
||||
on Zenodo), and post a curated summary of community-contributed benchmark links as a
|
||||
GitHub Discussion.
|
||||
|
||||
## Step 1: Load Cache and Determine Run Mode
|
||||
|
||||
Check cache memory for:
|
||||
- `official_repos`: set of GitHub repository full names (`owner/repo`) and Zenodo
|
||||
record IDs already identified as official SMT-LIB benchmark sets
|
||||
- `known_community_repos`: set of repo full names already listed in a previous report
|
||||
- `last_run_date`: ISO-8601 date string of the previous run
|
||||
|
||||
Use the cache to skip repos already classified. On the very first run (no cache),
|
||||
perform a full discovery pass. On subsequent runs focus on repos pushed or created
|
||||
since `last_run_date`.
|
||||
|
||||
## Step 2: Collect Official SMT-LIB Benchmark Sets to Exclude
|
||||
|
||||
### 2.1 Scrape smtlib.org
|
||||
|
||||
Fetch the SMT-LIB benchmarks page and extract all linked Zenodo DOIs and GitHub URLs:
|
||||
|
||||
```bash
|
||||
curl -s "https://smtlib.cs.uiowa.edu/benchmarks.shtml" -o /tmp/smtlib-benchmarks.html
|
||||
# Also try the main page and any mirror
|
||||
curl -s "https://smtlib.cs.uiowa.edu/" -o /tmp/smtlib-home.html
|
||||
```
|
||||
|
||||
Parse both files for:
|
||||
- Zenodo DOI links (`doi.org/10.5281/zenodo.*` or `zenodo.org/record/*`)
|
||||
- GitHub repository URLs (`github.com/...`)
|
||||
- Any other hosted benchmark archive links
|
||||
|
||||
### 2.2 Enumerate Zenodo SMT-LIB Community Records
|
||||
|
||||
Query the Zenodo API for all records in the SMT-LIB community:
|
||||
|
||||
```bash
|
||||
curl -s "https://zenodo.org/api/records?communities=smt-lib&size=100&page=1" \
|
||||
-o /tmp/zenodo-smtlib-page1.json
|
||||
|
||||
# Check if there are more pages (paginate until empty)
|
||||
curl -s "https://zenodo.org/api/records?communities=smt-lib&size=100&page=2" \
|
||||
-o /tmp/zenodo-smtlib-page2.json 2>/dev/null || true
|
||||
|
||||
curl -s "https://zenodo.org/api/records?communities=smt-lib&size=100&page=3" \
|
||||
-o /tmp/zenodo-smtlib-page3.json 2>/dev/null || true
|
||||
```
|
||||
|
||||
For each Zenodo record extract:
|
||||
- Record ID (e.g. `5827900`)
|
||||
- Title
|
||||
- Any GitHub repository URLs listed in the description or related identifiers
|
||||
|
||||
```bash
|
||||
python3 - <<'PYEOF'
|
||||
import json, re
|
||||
|
||||
def extract_github_repos(text):
|
||||
pattern = r'github\.com/([A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+)'
|
||||
return set(re.findall(pattern, text or ''))
|
||||
|
||||
official_repos = set()
|
||||
official_zenodo_ids = set()
|
||||
|
||||
for fname in ['/tmp/zenodo-smtlib-page1.json', '/tmp/zenodo-smtlib-page2.json',
|
||||
'/tmp/zenodo-smtlib-page3.json']:
|
||||
try:
|
||||
data = json.load(open(fname))
|
||||
except Exception:
|
||||
continue
|
||||
for hit in data.get('hits', {}).get('hits', []):
|
||||
rid = str(hit.get('id', ''))
|
||||
official_zenodo_ids.add(rid)
|
||||
metadata = hit.get('metadata', {})
|
||||
description = metadata.get('description', '')
|
||||
related = ' '.join(
|
||||
r.get('identifier', '')
|
||||
for r in metadata.get('related_identifiers', [])
|
||||
)
|
||||
title = metadata.get('title', '')
|
||||
for repo in extract_github_repos(description + ' ' + related + ' ' + title):
|
||||
official_repos.add(repo.lower().rstrip('.'))
|
||||
|
||||
with open('/tmp/smtlib-benchmarks.html') as f:
|
||||
html = f.read()
|
||||
for repo in extract_github_repos(html):
|
||||
official_repos.add(repo.lower().rstrip('.'))
|
||||
|
||||
print("OFFICIAL_ZENODO_IDS:", ','.join(sorted(official_zenodo_ids)) or '(none)')
|
||||
print("OFFICIAL_GITHUB_REPOS:", ','.join(sorted(official_repos)) or '(none)')
|
||||
PYEOF
|
||||
```
|
||||
|
||||
### 2.3 Well-Known Official Repository Patterns
|
||||
|
||||
Regardless of the above scrape, always exclude:
|
||||
- Any repo under the `SMT-LIB` GitHub organization (`SMT-LIB/*`)
|
||||
- Any repo whose name matches `smt-comp-*` that is under `SMT-Competition` org
|
||||
- The Z3 repo itself (`Z3Prover/z3`) and its forks
|
||||
|
||||
Combine all official sources into a single exclusion set stored at
|
||||
`/tmp/official_exclusions.txt` (one `owner/repo` pattern per line, lowercase).
|
||||
|
||||
## Step 3: Search GitHub for Community SMT-LIB Benchmark Repositories
|
||||
|
||||
Use multiple GitHub search strategies to find repos containing `.smt2` benchmark
|
||||
files that are NOT part of the official distribution. Search for repos updated
|
||||
since the last run date (or the last 90 days for the initial run).
|
||||
|
||||
Compute the cutoff date first:
|
||||
```bash
|
||||
CUTOFF=$(date -d "90 days ago" +%Y-%m-%d 2>/dev/null || date -v-90d +%Y-%m-%d)
|
||||
echo "Using cutoff date: $CUTOFF"
|
||||
```
|
||||
|
||||
### Search Strategies
|
||||
|
||||
Use the GitHub MCP server tools to run these searches:
|
||||
|
||||
1. **Topic search**: `topic:smtlib pushed:>$CUTOFF`
|
||||
2. **Topic search variant**: `topic:smt-lib pushed:>$CUTOFF`
|
||||
3. **Topic search variant**: `topic:smt2 pushed:>$CUTOFF`
|
||||
4. **Benchmark filename pattern**: `filename:*.smt2 pushed:>$CUTOFF` (limit to top results)
|
||||
5. **Benchmarks directory pattern**: `path:benchmarks *.smt2 in:path pushed:>$CUTOFF`
|
||||
6. **README mention**: `SMT-LIB benchmarks in:readme stars:>2 pushed:>$CUTOFF`
|
||||
7. **Organization-level search**: repos under `SMT-Competition` org, if any are not already excluded
|
||||
|
||||
For each search, collect: `full_name`, `html_url`, `description`, `stargazers_count`,
|
||||
`updated_at`, `pushed_at`, `default_branch`, `topics`.
|
||||
|
||||
Deduplicate by `full_name`. Limit to 200 total candidates before filtering.
|
||||
|
||||
## Step 4: Filter Out Official Benchmark Sets
|
||||
|
||||
For each candidate repo:
|
||||
|
||||
1. Check if `full_name.lower()` is in the exclusion set from Step 2.
|
||||
2. Check if the repo is owned by `SMT-LIB` or `SMT-Competition` org (case-insensitive).
|
||||
3. Check if the repo is a fork of a known official repo (if `fork: true` and parent is
|
||||
in the exclusion set).
|
||||
|
||||
Discard repos that match any of the above. Keep the rest as community benchmarks.
|
||||
|
||||
Also apply quality filters to reduce noise — skip repos that:
|
||||
- Have 0 stars and fewer than 3 `.smt2` files (likely a student homework or test repo
|
||||
with minimal public value); use your judgement — if the repo description clearly
|
||||
describes a research benchmark, keep it regardless of star count.
|
||||
- Were created but never pushed after creation (empty repos).
|
||||
- Have names that are clearly course assignment repositories
|
||||
(e.g. contain `homework`, `assignment`, `hw[0-9]`, `cs[0-9]{3}`).
|
||||
|
||||
## Step 5: Classify Remaining Repos
|
||||
|
||||
For each repo that survives filtering, classify it into one of these categories:
|
||||
|
||||
| Category | Description |
|
||||
|----------|-------------|
|
||||
| **Solver evaluation** | Benchmarks used to evaluate or compare SMT solvers |
|
||||
| **Verification** | Benchmarks from program verification or model checking |
|
||||
| **Security / CTF** | Benchmarks from security research or CTF challenges |
|
||||
| **Theory / logic** | Benchmarks exploring specific SMT theories or logics |
|
||||
| **Tool output** | Benchmarks generated by another tool (e.g. a compiler, fuzzer) |
|
||||
| **Education** | Course materials or tutorials with benchmark examples |
|
||||
| **Other / unknown** | Does not fit another category |
|
||||
|
||||
Base the classification on: repo description, README (fetch if web-fetch is available),
|
||||
topics, and directory structure. A single brief `web-fetch` of the repo's README is
|
||||
sufficient; do not fetch individual `.smt2` files.
|
||||
|
||||
Note the dominant SMT logic(s) present, if discernible from the description or topics
|
||||
(e.g. QF_BV, QF_LIA, QF_S, NIA, …).
|
||||
|
||||
## Step 6: Generate the Discussion Report
|
||||
|
||||
Create a GitHub Discussion. Use heading level 3 or deeper (`###`, `####`, …) for all
|
||||
section headers; never use `##` or `#` in the body.
|
||||
Wrap long tables in `<details>` tags to keep the report scannable.
|
||||
|
||||
Title: `[SMT-LIB Benchmarks] Community Benchmark Repository Survey — [Month YYYY]`
|
||||
|
||||
Structure the report as follows:
|
||||
|
||||
```markdown
|
||||
**Period covered**: [cutoff date] – [today's date]
|
||||
**Repositories found**: N community repos (after excluding M official sets)
|
||||
**New this run**: N (not listed in previous report)
|
||||
|
||||
### Overview
|
||||
|
||||
1–2 sentences summarising the breadth of community SMT-LIB benchmarks found.
|
||||
|
||||
### Community Benchmark Repositories
|
||||
|
||||
Use `###` for category headers. Within each category, list repos as a markdown table.
|
||||
For each repo include:
|
||||
- Repo link (`[owner/repo](html_url)`)
|
||||
- Stars
|
||||
- Last pushed date
|
||||
- Dominant logic(s) (if known)
|
||||
- Brief description (from repo description or README, max 120 chars)
|
||||
|
||||
#### Solver Evaluation
|
||||
|
||||
| Repository | ⭐ | Last pushed | Logic(s) | Description |
|
||||
|------------|-----|------------|---------|-------------|
|
||||
| [owner/repo](url) | N | YYYY-MM-DD | QF_BV, QF_LIA | … |
|
||||
|
||||
#### Verification
|
||||
|
||||
[same table structure]
|
||||
|
||||
#### Security / CTF
|
||||
|
||||
[same table structure]
|
||||
|
||||
#### Theory / Logic
|
||||
|
||||
[same table structure]
|
||||
|
||||
#### Tool Output
|
||||
|
||||
[same table structure]
|
||||
|
||||
#### Education
|
||||
|
||||
[same table structure]
|
||||
|
||||
#### Other / Unknown
|
||||
|
||||
[same table structure]
|
||||
|
||||
---
|
||||
|
||||
### Exclusions Applied
|
||||
|
||||
<details>
|
||||
<summary>Official SMT-LIB sets excluded from this report</summary>
|
||||
|
||||
List Zenodo record IDs and GitHub repos identified as official distributions.
|
||||
|
||||
| Source | Identifier | Notes |
|
||||
|--------|-----------|-------|
|
||||
| Zenodo | [10.5281/zenodo.XXXXXXX](https://zenodo.org/record/XXXXXXX) | Official QF_BV benchmark set |
|
||||
| GitHub | [SMT-LIB/benchmarks-non-incremental](https://github.com/SMT-LIB/benchmarks-non-incremental) | |
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
### Methodology
|
||||
|
||||
Brief note on search queries used, cutoff date, and any quality filters applied.
|
||||
```
|
||||
|
||||
## Step 7: Update Cache Memory
|
||||
|
||||
After posting the discussion, update cache memory with:
|
||||
- `official_repos`: updated exclusion set (union of previous + newly found)
|
||||
- `known_community_repos`: union of previous + repos listed in this report
|
||||
- `last_run_date`: today's ISO-8601 date
|
||||
- `report_url`: URL of the GitHub Discussion created
|
||||
|
||||
## Guidelines
|
||||
|
||||
- **Be conservative with exclusions**: when in doubt whether a repo is "official",
|
||||
keep it in the community list rather than silently dropping it.
|
||||
- **Be accurate**: only include repos that genuinely contain SMT-LIB `.smt2` files
|
||||
or clearly describe themselves as SMT-LIB benchmark collections.
|
||||
- **Avoid noise**: student homework repos and trivially small repos add clutter;
|
||||
apply the quality filters from Step 4 judiciously.
|
||||
- **No source code changes**: DO NOT create pull requests or modify any source files.
|
||||
- **No copyrighted content**: DO NOT reproduce benchmark file contents; only post
|
||||
links and metadata.
|
||||
- **Always cite sources**: include the full GitHub URL for every listed repository.
|
||||
- **Use cache**: skip repos already classified in a previous run to keep runtime short.
|
||||
- **Fail gracefully**: if GitHub search rate-limits the workflow, post whatever was
|
||||
collected so far with a note that the search was incomplete.
|
||||
|
||||
## Important Notes
|
||||
|
||||
- DO NOT create pull requests or modify source files.
|
||||
- DO close older SMT-LIB Benchmarks discussions automatically (configured).
|
||||
- DO always call `create_discussion` or `noop` before the workflow ends.
|
||||
Failing to produce any safe output triggers an automatic failure issue.
|
||||
- DO use cache memory to avoid re-processing repos already surveyed.
|
||||
- DO limit individual `web-fetch` calls (README fetches) to repos where the
|
||||
description alone is insufficient for classification.
|
||||
1429
.github/workflows/specbot-crash-analyzer.lock.yml
generated
vendored
Normal file
1429
.github/workflows/specbot-crash-analyzer.lock.yml
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
247
.github/workflows/specbot-crash-analyzer.md
vendored
Normal file
247
.github/workflows/specbot-crash-analyzer.md
vendored
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
---
|
||||
description: >
|
||||
Build Z3 in debug mode from the c3 branch, compile and run the specbot tests,
|
||||
identify root causes for any crashes, and post findings as a GitHub Discussion.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
timeout-minutes: 120
|
||||
|
||||
permissions: read-all
|
||||
|
||||
network: defaults
|
||||
|
||||
tools:
|
||||
cache-memory: true
|
||||
github:
|
||||
toolsets: [default, discussions]
|
||||
bash: [":*"]
|
||||
edit: {}
|
||||
|
||||
safe-outputs:
|
||||
create-discussion:
|
||||
title-prefix: "[Specbot] "
|
||||
category: "Agentic Workflows"
|
||||
close-older-discussions: true
|
||||
missing-tool:
|
||||
create-issue: true
|
||||
noop:
|
||||
report-as-issue: false
|
||||
|
||||
steps:
|
||||
- name: Checkout c3 branch
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
ref: c3
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y cmake ninja-build python3 gcc g++ 2>&1 | tail -5
|
||||
|
||||
- name: Build Z3 in debug mode
|
||||
id: build-z3
|
||||
continue-on-error: true
|
||||
run: |
|
||||
mkdir -p build/debug specbot-results
|
||||
cd build/debug
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../.. 2>&1 | tee ../../specbot-results/cmake.log
|
||||
ninja 2>&1 | tee ../../specbot-results/build.log
|
||||
BUILD_EXIT=$?
|
||||
cd ../..
|
||||
echo "build_exit=${BUILD_EXIT}" >> specbot-results/build-status.txt
|
||||
ls -la build/debug/libz3* build/debug/*.so* 2>/dev/null >> specbot-results/build-status.txt || echo "Library not found" >> specbot-results/build-status.txt
|
||||
exit $BUILD_EXIT
|
||||
|
||||
- name: Compile specbot tests
|
||||
continue-on-error: true
|
||||
run: |
|
||||
mkdir -p specbot-results
|
||||
gcc -g -O0 \
|
||||
-I src/api \
|
||||
specbot/test_specbot_seq.c \
|
||||
-L build/debug \
|
||||
-lz3 \
|
||||
-Wl,-rpath,"${GITHUB_WORKSPACE}/build/debug" \
|
||||
-o specbot-results/test_specbot_seq \
|
||||
2>&1 | tee specbot-results/compile_specbot_seq.log
|
||||
echo "compile_specbot_seq_exit=$?" >> specbot-results/compile-status.txt
|
||||
|
||||
gcc -g -O0 \
|
||||
-I src/api \
|
||||
specbot/test_deeptest_seq.c \
|
||||
-L build/debug \
|
||||
-lz3 \
|
||||
-Wl,-rpath,"${GITHUB_WORKSPACE}/build/debug" \
|
||||
-o specbot-results/test_deeptest_seq \
|
||||
2>&1 | tee specbot-results/compile_deeptest_seq.log
|
||||
echo "compile_deeptest_seq_exit=$?" >> specbot-results/compile-status.txt
|
||||
|
||||
- name: Run specbot tests
|
||||
continue-on-error: true
|
||||
run: |
|
||||
mkdir -p specbot-results
|
||||
if [ -f specbot-results/test_specbot_seq ]; then
|
||||
LD_LIBRARY_PATH="${GITHUB_WORKSPACE}/build/debug" timeout 120 specbot-results/test_specbot_seq > specbot-results/test_specbot_seq.log 2>&1
|
||||
SPECBOT_EXIT=$?
|
||||
echo "specbot_seq_exit=${SPECBOT_EXIT}" >> specbot-results/test-status.txt
|
||||
else
|
||||
echo "Binary not compiled" > specbot-results/test_specbot_seq.log
|
||||
echo "specbot_seq_exit=127" >> specbot-results/test-status.txt
|
||||
fi
|
||||
|
||||
if [ -f specbot-results/test_deeptest_seq ]; then
|
||||
LD_LIBRARY_PATH="${GITHUB_WORKSPACE}/build/debug" timeout 120 specbot-results/test_deeptest_seq > specbot-results/test_deeptest_seq.log 2>&1
|
||||
DEEPTEST_EXIT=$?
|
||||
echo "deeptest_seq_exit=${DEEPTEST_EXIT}" >> specbot-results/test-status.txt
|
||||
else
|
||||
echo "Binary not compiled" > specbot-results/test_deeptest_seq.log
|
||||
echo "deeptest_seq_exit=127" >> specbot-results/test-status.txt
|
||||
fi
|
||||
|
||||
---
|
||||
|
||||
# Specbot Crash Analyzer
|
||||
|
||||
## Job Description
|
||||
|
||||
Your name is ${{ github.workflow }}. You are an expert C/C++ and SMT solver analyst for the Z3 theorem prover
|
||||
repository `${{ github.repository }}`. The pre-steps above have already built Z3 in debug mode from the `c3`
|
||||
branch, compiled and run the specbot test suite, and saved all output to the `specbot-results/` directory in
|
||||
the workspace (`${{ github.workspace }}/specbot-results/`). Your task is to analyze those results, diagnose
|
||||
any crash root causes by reading the relevant source files, and publish a structured findings report as a
|
||||
GitHub Discussion.
|
||||
|
||||
**Do not try to build Z3 or run tests yourself.** All build and test output is already in `specbot-results/`.
|
||||
|
||||
## Your Task
|
||||
|
||||
### 1. Read the Pre-Generated Results
|
||||
|
||||
All build and test outputs are in `specbot-results/` (relative to the workspace root). Read each file:
|
||||
|
||||
```bash
|
||||
# Build status
|
||||
cat specbot-results/build-status.txt 2>/dev/null || echo "No build status"
|
||||
|
||||
# Compile status
|
||||
cat specbot-results/compile-status.txt 2>/dev/null || echo "No compile status"
|
||||
|
||||
# Test status
|
||||
cat specbot-results/test-status.txt 2>/dev/null || echo "No test status"
|
||||
|
||||
# Test output from test_specbot_seq
|
||||
cat specbot-results/test_specbot_seq.log 2>/dev/null || echo "No test_specbot_seq output"
|
||||
|
||||
# Test output from test_deeptest_seq
|
||||
cat specbot-results/test_deeptest_seq.log 2>/dev/null || echo "No test_deeptest_seq output"
|
||||
|
||||
# Last 30 lines of the build log
|
||||
tail -30 specbot-results/build.log 2>/dev/null || echo "No build log"
|
||||
```
|
||||
|
||||
If `specbot-results/build-status.txt` shows `build_exit=0`, the build succeeded.
|
||||
If it shows a non-zero exit, include the last 50 lines of `specbot-results/build.log` in the report
|
||||
under a "Build Failure" section.
|
||||
|
||||
If `specbot-results/compile-status.txt` shows a non-zero exit for a test, include the compile error
|
||||
from `specbot-results/compile_specbot_seq.log` or `specbot-results/compile_deeptest_seq.log`.
|
||||
|
||||
Collect every line containing `CRASH` or `ABORT` from the test log files — these are the crashes to analyze.
|
||||
|
||||
### 2. Diagnose Each Crash
|
||||
|
||||
For each crashed test function, perform the following analysis:
|
||||
|
||||
1. **Identify the test body**: read `specbot/test_specbot_seq.c` or `specbot/test_deeptest_seq.c`
|
||||
to understand what Z3 API calls the test makes and what invariants it exercises.
|
||||
|
||||
2. **Find the likely crash site**: the test exercises the Z3 Nielsen/nseq string solver. Relevant source files are:
|
||||
- `src/smt/seq_solver.h` and `src/smt/seq_solver.cpp` (or nearby files)
|
||||
- `src/smt/seq_axioms.cpp`, `src/smt/seq_eq_solver.cpp`, `src/smt/seq_regex.cpp`
|
||||
- `src/math/lp/` for length-arithmetic paths
|
||||
- `src/api/z3_api.h` for the public API entry points
|
||||
|
||||
Use `grep` and `view` to locate assertion macros, `UNREACHABLE()`, `SASSERT`, or `throw` statements
|
||||
in the code paths exercised by the failing test. Example:
|
||||
```bash
|
||||
grep -rn "SASSERT\|UNREACHABLE\|Z3_CATCH" src/smt/seq_solver.cpp 2>/dev/null | head -30
|
||||
```
|
||||
|
||||
3. **Hypothesize root cause**: based on the Z3 API calls in the test and the assertion/throw sites in
|
||||
the solver source, state the most likely root cause. Common categories include:
|
||||
- Violated invariant (SASSERT/UNREACHABLE hit due to unexpected solver state)
|
||||
- Use-after-free or dangling reference during push/pop
|
||||
- Unhandled edge case in Nielsen graph construction
|
||||
- Missing theory-combination lemma between string length and integer arithmetic
|
||||
|
||||
4. **Suggest a fix**: propose a minimal, concrete fix — e.g., a guard condition, an additional lemma,
|
||||
a missing reference-count increment, or a missing case in a switch/match.
|
||||
|
||||
### 3. Generate the Report
|
||||
|
||||
After analyzing all crashes, produce a structured GitHub Discussion in the "Agentic Workflows" category
|
||||
using `create-discussion`.
|
||||
|
||||
The discussion body must follow this structure (use `###` and lower for headers):
|
||||
|
||||
```
|
||||
### Summary
|
||||
|
||||
- Build: Debug (CMake + Ninja, c3 branch)
|
||||
- Tests compiled: N
|
||||
- Tests run: N
|
||||
- Tests passed: N
|
||||
- Tests crashed: N
|
||||
- Tests timed out: N
|
||||
|
||||
### Crash Findings
|
||||
|
||||
For each crash, one subsection:
|
||||
|
||||
#### <test function name>
|
||||
|
||||
**Test file**: `specbot/test_specbot_seq.c` or `specbot/test_deeptest_seq.c`
|
||||
|
||||
**Observed failure**: ABORT/CRASH — one-line description of what was caught
|
||||
|
||||
**Root cause hypothesis**: explanation of which assertion or code path was hit and why
|
||||
|
||||
**Suggested fix**: concrete proposed change (file, function, what to add/change)
|
||||
|
||||
---
|
||||
|
||||
### Tests Passed
|
||||
|
||||
List of test names that passed.
|
||||
|
||||
<details>
|
||||
<summary><b>Full Test Output</b></summary>
|
||||
|
||||
Raw stdout/stderr from both test binaries.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Build Log</b></summary>
|
||||
|
||||
Last 30 lines of the ninja build output.
|
||||
|
||||
</details>
|
||||
```
|
||||
|
||||
If there are no crashes at all, write a "No Crashes Found" summary celebrating that all tests passed,
|
||||
and include the full test output in a collapsible section.
|
||||
|
||||
Use `mentions: false` behavior — do not mention any GitHub usernames in the report.
|
||||
|
||||
Format workflow run references as: `[§${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`.
|
||||
|
||||
## Usage
|
||||
|
||||
Trigger via **Actions → Specbot Crash Analyzer → Run workflow** on any branch. The pre-steps
|
||||
always check out the `c3` branch where `specbot/test_specbot_seq.c` and
|
||||
`specbot/test_deeptest_seq.c` live, build Z3, run the tests, and save results to `specbot-results/`.
|
||||
The agent then analyzes the results and posts a discussion to the "Agentic Workflows" category.
|
||||
2
.github/workflows/tactic-to-simplifier.md
vendored
2
.github/workflows/tactic-to-simplifier.md
vendored
|
|
@ -19,8 +19,6 @@ tools:
|
|||
github:
|
||||
toolsets: [default]
|
||||
bash: [":*"]
|
||||
glob: {}
|
||||
view: {}
|
||||
|
||||
safe-outputs:
|
||||
create-issue:
|
||||
|
|
|
|||
1323
.github/workflows/tptp-benchmark.lock.yml
generated
vendored
Normal file
1323
.github/workflows/tptp-benchmark.lock.yml
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
546
.github/workflows/tptp-benchmark.md
vendored
Normal file
546
.github/workflows/tptp-benchmark.md
vendored
Normal file
|
|
@ -0,0 +1,546 @@
|
|||
---
|
||||
description: >
|
||||
Weekly benchmark of Z3's TPTP front-end against 500 random TPTP problems.
|
||||
Downloads TPTP benchmarks from tptp.org, resolves axiom dependencies,
|
||||
skips large problems, runs each with a 5-second timeout, and posts a
|
||||
discrepancy/crash report as a GitHub discussion.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 6 * * 1"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: read-all
|
||||
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
- tptp.org
|
||||
|
||||
tools:
|
||||
bash: true
|
||||
github:
|
||||
toolsets: [default]
|
||||
|
||||
safe-outputs:
|
||||
create-discussion:
|
||||
title-prefix: "[TPTP Benchmark] "
|
||||
category: "Agentic Workflows"
|
||||
close-older-discussions: true
|
||||
expires: 14d
|
||||
missing-tool:
|
||||
create-issue: true
|
||||
noop:
|
||||
report-as-issue: false
|
||||
|
||||
timeout-minutes: 300
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
sudo apt-get update -y -q
|
||||
sudo apt-get install -y cmake ninja-build python3 wget curl bc
|
||||
|
||||
- name: Build Z3
|
||||
run: |
|
||||
mkdir -p /tmp/z3-build
|
||||
cd /tmp/z3-build
|
||||
cmake "$GITHUB_WORKSPACE" \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DZ3_BUILD_TEST_EXECUTABLES=OFF
|
||||
ninja -j$(nproc) z3
|
||||
./z3 --version
|
||||
|
||||
---
|
||||
|
||||
# TPTP Front-End Benchmark
|
||||
|
||||
## Job Description
|
||||
|
||||
Your name is ${{ github.workflow }}. You are an expert testing engineer for the Z3 theorem prover. Your task is to:
|
||||
|
||||
1. Verify the Z3 binary built by the pre-flight step is available
|
||||
2. Download the TPTP benchmark library from tptp.org
|
||||
3. Select 500 random small-to-medium problems (with their axiom dependencies)
|
||||
4. Run each problem through Z3's TPTP front-end with a 5-second timeout
|
||||
5. Compare Z3's output against the expected SZS status declared in each problem file
|
||||
6. Post a detailed report as a GitHub Discussion summarising discrepancies and crashes
|
||||
|
||||
**Repository**: ${{ github.repository }}
|
||||
**Workspace**: ${{ github.workspace }}
|
||||
|
||||
## Phase 1: Verify Z3 Binary
|
||||
|
||||
Z3 was built by the workflow pre-flight step and is available at `/tmp/z3-build/z3`.
|
||||
Confirm the binary is present and functional:
|
||||
|
||||
```bash
|
||||
/tmp/z3-build/z3 --version
|
||||
```
|
||||
|
||||
If the binary is missing or returns an error, call the `noop` safe-output with a message describing the problem and stop.
|
||||
|
||||
Once confirmed, call `noop` with `"Z3 binary verified. Downloading TPTP benchmark library — this may take a few minutes."` to keep the safe-output session alive.
|
||||
|
||||
## Phase 2: Download the TPTP Problem Library
|
||||
|
||||
Find the latest TPTP release and download the full archive.
|
||||
|
||||
```bash
|
||||
# Find the latest TPTP distribution version by fetching the directory listing
|
||||
TPTP_DIST_URL="https://tptp.org/TPTP/Distribution/"
|
||||
LATEST_TGZ=$(curl -sL "$TPTP_DIST_URL" \
|
||||
| grep -oP 'TPTP-v[0-9]+\.[0-9]+\.[0-9]+\.tgz' \
|
||||
| sort -V | tail -1)
|
||||
|
||||
if [ -z "$LATEST_TGZ" ]; then
|
||||
echo "ERROR: Could not determine latest TPTP version from $TPTP_DIST_URL"
|
||||
# Fall back to a known stable version
|
||||
LATEST_TGZ="TPTP-v9.0.0.tgz"
|
||||
fi
|
||||
|
||||
echo "Downloading $LATEST_TGZ ..."
|
||||
mkdir -p /tmp/tptp_download
|
||||
wget -q --show-progress \
|
||||
"${TPTP_DIST_URL}${LATEST_TGZ}" \
|
||||
-O /tmp/tptp_download/tptp.tgz
|
||||
|
||||
echo "Extracting TPTP library..."
|
||||
mkdir -p /tmp/tptp
|
||||
tar -xzf /tmp/tptp_download/tptp.tgz -C /tmp/tptp --strip-components=1 2>&1 | tail -5
|
||||
|
||||
# Verify extraction
|
||||
if [ ! -d /tmp/tptp/Problems ] || [ ! -d /tmp/tptp/Axioms ]; then
|
||||
echo "ERROR: TPTP extraction failed — Problems/ or Axioms/ directory not found"
|
||||
ls /tmp/tptp/
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TPTP_ROOT=/tmp/tptp
|
||||
echo "TPTP library extracted to $TPTP_ROOT"
|
||||
echo "Problem domains available:"
|
||||
ls "$TPTP_ROOT/Problems/" | wc -l
|
||||
echo "Axiom files available:"
|
||||
ls "$TPTP_ROOT/Axioms/" | wc -l
|
||||
```
|
||||
|
||||
If the download or extraction fails, call `noop` with the error details and stop.
|
||||
|
||||
Call `noop` with `"TPTP library downloaded and extracted. Selecting 500 benchmark problems — filtering by size."` to keep the session alive.
|
||||
|
||||
## Phase 3: Select 500 Benchmark Problems
|
||||
|
||||
Filter out large problems and problems that depend on large axiom files, then take a random sample of 500.
|
||||
|
||||
Save this script to `/tmp/select_benchmarks.py` and run it:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Select 500 random TPTP problems that:
|
||||
- Have a known, conclusive expected status (Theorem, Unsatisfiable,
|
||||
CounterSatisfiable, Satisfiable) OR Unknown/Open status.
|
||||
- Are not "large" (problem file <= 50 KB).
|
||||
- Do not include any axiom file larger than 100 KB.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import random
|
||||
import sys
|
||||
|
||||
TPTP_ROOT = "/tmp/tptp"
|
||||
PROBLEMS_DIR = os.path.join(TPTP_ROOT, "Problems")
|
||||
AXIOMS_DIR = os.path.join(TPTP_ROOT, "Axioms")
|
||||
MAX_PROBLEM_SIZE = 50 * 1024 # 50 KB
|
||||
MAX_AXIOM_SIZE = 100 * 1024 # 100 KB
|
||||
SAMPLE_SIZE = 500
|
||||
OUTPUT_FILE = "/tmp/selected_benchmarks.txt"
|
||||
|
||||
include_re = re.compile(r"include\s*\(\s*['\"]([^'\"]+)['\"]", re.IGNORECASE)
|
||||
status_re = re.compile(r"%\s*Status\s*:\s*(\S+)", re.IGNORECASE)
|
||||
|
||||
def axiom_sizes_ok(problem_path):
|
||||
"""Return True if all included axiom files exist and are <= MAX_AXIOM_SIZE."""
|
||||
try:
|
||||
with open(problem_path, encoding="utf-8", errors="replace") as f:
|
||||
content = f.read(4096) # header is in first few KB
|
||||
except OSError:
|
||||
return False
|
||||
for m in include_re.finditer(content):
|
||||
axiom_rel = m.group(1) # e.g. "Axioms/AGT001+0.ax"
|
||||
axiom_path = os.path.join(TPTP_ROOT, axiom_rel)
|
||||
if not os.path.exists(axiom_path):
|
||||
return False # axiom missing — skip
|
||||
if os.path.getsize(axiom_path) > MAX_AXIOM_SIZE:
|
||||
return False # axiom too large — skip
|
||||
return True
|
||||
|
||||
candidates = []
|
||||
skipped_size = 0
|
||||
skipped_axiom = 0
|
||||
|
||||
for domain in sorted(os.listdir(PROBLEMS_DIR)):
|
||||
domain_dir = os.path.join(PROBLEMS_DIR, domain)
|
||||
if not os.path.isdir(domain_dir):
|
||||
continue
|
||||
for fname in os.listdir(domain_dir):
|
||||
if not fname.endswith(".p"):
|
||||
continue
|
||||
fpath = os.path.join(domain_dir, fname)
|
||||
size = os.path.getsize(fpath)
|
||||
if size > MAX_PROBLEM_SIZE:
|
||||
skipped_size += 1
|
||||
continue
|
||||
if not axiom_sizes_ok(fpath):
|
||||
skipped_axiom += 1
|
||||
continue
|
||||
candidates.append(fpath)
|
||||
|
||||
print(f"Total candidates (after filtering): {len(candidates)}", flush=True)
|
||||
print(f" Skipped — problem too large : {skipped_size}", flush=True)
|
||||
print(f" Skipped — axiom too large : {skipped_axiom}", flush=True)
|
||||
|
||||
if len(candidates) == 0:
|
||||
print("ERROR: No suitable benchmark problems found.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if len(candidates) > SAMPLE_SIZE:
|
||||
random.seed(42)
|
||||
selected = random.sample(candidates, SAMPLE_SIZE)
|
||||
else:
|
||||
selected = candidates
|
||||
|
||||
selected.sort()
|
||||
with open(OUTPUT_FILE, "w") as f:
|
||||
f.write("\n".join(selected) + "\n")
|
||||
|
||||
print(f"Selected {len(selected)} problems → {OUTPUT_FILE}", flush=True)
|
||||
```
|
||||
|
||||
Run the script:
|
||||
|
||||
```bash
|
||||
python3 /tmp/select_benchmarks.py
|
||||
SELECTED=$(wc -l < /tmp/selected_benchmarks.txt)
|
||||
echo "Benchmark set: $SELECTED problems"
|
||||
```
|
||||
|
||||
If no problems are found, call `noop` with an error message and stop.
|
||||
|
||||
Call `noop` with `"$SELECTED problems selected. Starting benchmark run with 5-second timeout per problem — this will take approximately $(( SELECTED * 7 / 60 )) minutes."` to keep the session alive.
|
||||
|
||||
## Phase 4: Run Benchmarks
|
||||
|
||||
Save the following script to `/tmp/run_tptp_benchmarks.sh`, make it executable, and run it.
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
Z3=/tmp/z3-build/z3
|
||||
TPTP_ROOT=/tmp/tptp
|
||||
TIMEOUT_HARD=8 # outer OS-level guard (seconds; 3 s beyond Z3's -T:5)
|
||||
Z3_TIMEOUT=5 # Z3 internal timeout: -T:N sets N-second limit (uppercase -T is seconds)
|
||||
|
||||
RESULTS=/tmp/tptp_results.tsv
|
||||
PROBLEM_LIST=/tmp/selected_benchmarks.txt
|
||||
|
||||
echo -e "file\texpected\tactual\ttime_s\tnotes" > "$RESULTS"
|
||||
|
||||
# Helper: extract the expected SZS status from the TPTP problem header.
|
||||
get_expected_status() {
|
||||
local file="$1"
|
||||
# Look for lines like: "% Status : Theorem"
|
||||
grep -m1 -iP '%\s*Status\s*:\s*\K\S+' "$file" 2>/dev/null || echo "Unknown"
|
||||
}
|
||||
|
||||
# Helper: run z3 on a single TPTP problem with timeout.
|
||||
run_benchmark() {
|
||||
local file="$1"
|
||||
local start end elapsed output exit_code verdict
|
||||
|
||||
start=$(date +%s%3N) # milliseconds since epoch
|
||||
output=$(TPTP="$TPTP_ROOT" timeout "$TIMEOUT_HARD" \
|
||||
"$Z3" -tptp -T:"$Z3_TIMEOUT" "$file" 2>&1) || exit_code=$?
|
||||
exit_code=${exit_code:-0}
|
||||
end=$(date +%s%3N)
|
||||
elapsed=$(echo "scale=3; ($end - $start) / 1000" | bc)
|
||||
|
||||
# Extract SZS status line from output
|
||||
szs_line=$(echo "$output" | grep -m1 "% SZS status" || true)
|
||||
|
||||
if [ -n "$szs_line" ]; then
|
||||
# Parse the status keyword (e.g. "Theorem", "CounterSatisfiable", "GaveUp")
|
||||
verdict=$(echo "$szs_line" | grep -oP '% SZS status \K\S+' || echo "Unknown")
|
||||
elif [ "$exit_code" -eq 124 ]; then
|
||||
verdict="Timeout"
|
||||
elif [ "$exit_code" -ne 0 ]; then
|
||||
verdict="Crash"
|
||||
else
|
||||
verdict="NoOutput"
|
||||
fi
|
||||
|
||||
echo "$verdict $elapsed"
|
||||
}
|
||||
|
||||
COUNTER=0
|
||||
TOTAL=$(wc -l < "$PROBLEM_LIST")
|
||||
|
||||
while IFS= read -r problem_file; do
|
||||
COUNTER=$((COUNTER + 1))
|
||||
|
||||
expected=$(get_expected_status "$problem_file")
|
||||
result_line=$(run_benchmark "$problem_file")
|
||||
actual=$(echo "$result_line" | cut -d' ' -f1)
|
||||
elapsed=$(echo "$result_line" | cut -d' ' -f2)
|
||||
fname=$(basename "$problem_file")
|
||||
|
||||
# Classify notes
|
||||
notes=""
|
||||
# Soundness discrepancy: both answers are conclusive but conflict
|
||||
conclusive_expected=false
|
||||
conclusive_actual=false
|
||||
case "$expected" in
|
||||
Theorem|Unsatisfiable) conclusive_expected=true ;;
|
||||
Satisfiable|CounterSatisfiable) conclusive_expected=true ;;
|
||||
esac
|
||||
case "$actual" in
|
||||
Theorem|Unsatisfiable) conclusive_actual=true ;;
|
||||
Satisfiable|CounterSatisfiable) conclusive_actual=true ;;
|
||||
esac
|
||||
|
||||
if $conclusive_expected && $conclusive_actual; then
|
||||
# Map expected to the Z3 output equivalents for comparison
|
||||
# Theorem (has-conjecture unsat) matches "Theorem"
|
||||
# Unsatisfiable (no-conjecture unsat) matches "Unsatisfiable"
|
||||
# Satisfiable (no-conjecture sat) matches "Satisfiable"
|
||||
# CounterSatisfiable (has-conjecture sat) matches "CounterSatisfiable"
|
||||
if [ "$expected" != "$actual" ]; then
|
||||
# Check for sat/unsat polarity conflict
|
||||
sat_expected=false; sat_actual=false
|
||||
case "$expected" in Satisfiable|CounterSatisfiable) sat_expected=true ;; esac
|
||||
case "$actual" in Satisfiable|CounterSatisfiable) sat_actual=true ;; esac
|
||||
if [ "$sat_expected" != "$sat_actual" ]; then
|
||||
notes="SOUNDNESS_ERROR"
|
||||
else
|
||||
notes="STATUS_MISMATCH"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$actual" = "Crash" ]; then
|
||||
notes="CRASH"
|
||||
fi
|
||||
|
||||
echo -e "$fname\t$expected\t$actual\t$elapsed\t$notes" >> "$RESULTS"
|
||||
|
||||
if [ -n "$notes" ]; then
|
||||
echo "[$COUNTER/$TOTAL] $fname expected=$expected actual=$actual time=${elapsed}s *** $notes ***"
|
||||
elif [ $((COUNTER % 50)) -eq 0 ]; then
|
||||
echo "[$COUNTER/$TOTAL] Progress checkpoint last=$fname actual=$actual time=${elapsed}s"
|
||||
fi
|
||||
|
||||
done < "$PROBLEM_LIST"
|
||||
|
||||
echo "Benchmark run complete: $COUNTER problems processed. Results → $RESULTS"
|
||||
```
|
||||
|
||||
Run it:
|
||||
|
||||
```bash
|
||||
chmod +x /tmp/run_tptp_benchmarks.sh
|
||||
/tmp/run_tptp_benchmarks.sh
|
||||
```
|
||||
|
||||
Do not skip any file in the list.
|
||||
|
||||
## Phase 5: Analyze Results
|
||||
|
||||
Save the following script to `/tmp/analyze_tptp.py` and run it:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""Compute summary statistics from the TPTP benchmark TSV."""
|
||||
import csv
|
||||
|
||||
RESULTS_FILE = "/tmp/tptp_results.tsv"
|
||||
|
||||
rows = []
|
||||
with open(RESULTS_FILE, newline="") as f:
|
||||
reader = csv.DictReader(f, delimiter="\t")
|
||||
for row in reader:
|
||||
rows.append(row)
|
||||
|
||||
total = len(rows)
|
||||
|
||||
# Verdict counts
|
||||
from collections import Counter, defaultdict
|
||||
actual_counts = Counter(r["actual"] for r in rows)
|
||||
expected_counts = Counter(r["expected"] for r in rows)
|
||||
|
||||
# Flagged rows
|
||||
soundness_errors = [r for r in rows if r["notes"] == "SOUNDNESS_ERROR"]
|
||||
status_mismatches = [r for r in rows if r["notes"] == "STATUS_MISMATCH"]
|
||||
crashes = [r for r in rows if r["notes"] == "CRASH"]
|
||||
timeouts = [r for r in rows if r["actual"] == "Timeout"]
|
||||
gave_up = [r for r in rows if r["actual"] == "GaveUp"]
|
||||
|
||||
# Solved correctly (expected matches actual for conclusive verdicts)
|
||||
conclusive_expected = {"Theorem", "Unsatisfiable", "Satisfiable", "CounterSatisfiable"}
|
||||
correct = [r for r in rows
|
||||
if r["expected"] in conclusive_expected
|
||||
and r["actual"] == r["expected"]]
|
||||
|
||||
print(f"TOTAL={total}")
|
||||
print(f"CORRECT={len(correct)}")
|
||||
print(f"TIMEOUTS={len(timeouts)}")
|
||||
print(f"GAVE_UP={len(gave_up)}")
|
||||
print(f"CRASHES={len(crashes)}")
|
||||
print(f"SOUNDNESS_ERRORS={len(soundness_errors)}")
|
||||
print(f"STATUS_MISMATCHES={len(status_mismatches)}")
|
||||
|
||||
print("\n--- Actual verdict breakdown ---")
|
||||
for v, c in sorted(actual_counts.items()):
|
||||
print(f" {v}: {c}")
|
||||
|
||||
print("\n--- Expected status breakdown ---")
|
||||
for v, c in sorted(expected_counts.items()):
|
||||
print(f" {v}: {c}")
|
||||
|
||||
if soundness_errors:
|
||||
print(f"\n--- SOUNDNESS ERRORS ({len(soundness_errors)}) ---")
|
||||
for r in soundness_errors:
|
||||
print(f" {r['file']} expected={r['expected']} actual={r['actual']}")
|
||||
|
||||
if crashes:
|
||||
print(f"\n--- CRASHES ({len(crashes)}) ---")
|
||||
for r in crashes:
|
||||
print(f" {r['file']} expected={r['expected']}")
|
||||
|
||||
if status_mismatches:
|
||||
print(f"\n--- STATUS MISMATCHES ({len(status_mismatches)}) ---")
|
||||
for r in status_mismatches[:20]:
|
||||
print(f" {r['file']} expected={r['expected']} actual={r['actual']}")
|
||||
```
|
||||
|
||||
Run the analysis:
|
||||
|
||||
```bash
|
||||
python3 /tmp/analyze_tptp.py
|
||||
```
|
||||
|
||||
## Phase 6: Generate and Post the Discussion Report
|
||||
|
||||
Read the TSV at `/tmp/tptp_results.tsv` and the analysis output, then compose a Markdown report and call `create_discussion`.
|
||||
|
||||
The report should use `###` or lower for all headers (never `#` or `##`). Use collapsible `<details>` sections for large tables.
|
||||
|
||||
Use this structure:
|
||||
|
||||
```markdown
|
||||
**Date**: <today's date>
|
||||
**Branch**: master
|
||||
**Commit**: `<short SHA>` (run `git rev-parse --short HEAD` in ${{ github.workspace }} to get the SHA)
|
||||
**Workflow Run**: [${{ github.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
||||
**TPTP version**: <downloaded version>
|
||||
**Problems benchmarked**: <N> (random sample, timeout 5 s per problem)
|
||||
|
||||
---
|
||||
|
||||
### Summary
|
||||
|
||||
| Metric | Count |
|
||||
|--------|-------|
|
||||
| Total problems run | N |
|
||||
| Correct (expected = actual) | N |
|
||||
| Timeouts | N |
|
||||
| GaveUp (within time budget) | N |
|
||||
| Crashes / errors | N |
|
||||
| Soundness errors (sat↔unsat conflict) | N |
|
||||
| Status mismatches (Theorem vs Unsatisfiable etc.) | N |
|
||||
|
||||
### Expected Status Distribution
|
||||
|
||||
| Expected Status | Count |
|
||||
|----------------|-------|
|
||||
| Theorem | N |
|
||||
| Unsatisfiable | N |
|
||||
| Satisfiable | N |
|
||||
| CounterSatisfiable | N |
|
||||
| Unknown / Open | N |
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Critical: Soundness Errors
|
||||
|
||||
[List ALL files where Z3 returned a conclusive answer that contradicts the expected answer
|
||||
(e.g., expected Theorem but got CounterSatisfiable). If none, write "None detected."]
|
||||
|
||||
### 💥 Crashes
|
||||
|
||||
[List ALL files where Z3 crashed (non-zero exit, no SZS output, not a timeout).
|
||||
Include filename and expected status. If none, write "None detected."]
|
||||
|
||||
### Status Mismatches
|
||||
|
||||
[Files where both answers are conclusive but differ in Theorem vs Unsatisfiable polarity
|
||||
(e.g., expected Theorem but actual Unsatisfiable). These may indicate conjecture-handling
|
||||
differences rather than soundness bugs. If none, write "None detected."]
|
||||
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>View all Timeouts (problems where Z3 exceeded the 5-second limit)</summary>
|
||||
|
||||
| # | File | Expected Status |
|
||||
|---|------|----------------|
|
||||
[First 100 timeout rows]
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>View full per-problem results table</summary>
|
||||
|
||||
| # | File | Expected | Actual | Time (s) | Notes |
|
||||
|---|------|----------|--------|----------|-------|
|
||||
[All rows, or first 500 if over limit]
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
### Recommendations
|
||||
|
||||
[Based on the findings, list actionable items. E.g.: investigate soundness errors,
|
||||
file crash bugs, note domains where Z3 consistently times out.]
|
||||
```
|
||||
|
||||
Post the discussion using the `create_discussion` safe output. The title should be
|
||||
`[TPTP Benchmark] master — <date>`.
|
||||
|
||||
## Safe Output Guarantee
|
||||
|
||||
You **MUST** call either `create_discussion` or `noop` before the workflow ends:
|
||||
|
||||
- **Full success**: Call `create_discussion` with the complete report.
|
||||
- **Partial results** (some problems ran): Call `create_discussion` with whatever results are available and a note about incomplete execution.
|
||||
- **Download failure**: Call `noop` with the download error details.
|
||||
- **No problems selected**: Call `noop` explaining why no problems were found.
|
||||
- **Binary missing**: If `/tmp/z3-build/z3` is unexpectedly absent, call `noop` with that detail and stop.
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Build failure handling**: Z3 was built before the agent loaded. If the binary is missing or non-functional, call `noop` with the error and stop.
|
||||
- **TPTP environment variable**: Set `TPTP=/tmp/tptp` when invoking `z3 -tptp` so that `include()` directives in problem files resolve correctly against the downloaded Axioms directory.
|
||||
- **Timeout detection**: Use `timeout 8` as the outer OS-level guard (3 seconds beyond Z3's `-T:5`) to allow Z3 to exit cleanly before the shell kills it. If the exit code from `timeout` is 124, record the verdict as `Timeout`.
|
||||
- **Crash detection**: A crash is a non-zero exit code with no `% SZS status` line in the output and no timeout. Record it separately from `GaveUp`.
|
||||
- **SZS status semantics**: Z3 outputs `Theorem` (not `Unsatisfiable`) when it proves a conjecture; `CounterSatisfiable` (not `Satisfiable`) when it finds a counterexample to a conjecture. A status mismatch between `Theorem` and `Unsatisfiable` for the same problem may be innocuous and depends on whether the problem file uses a conjecture formula.
|
||||
- **Report soundness bugs prominently**: Any case where the polarity of the answer conflicts (expected Theorem/Unsatisfiable but got CounterSatisfiable/Satisfiable, or vice versa) is a potential soundness bug and must be highlighted as critical.
|
||||
- **Keep progress log**: Print a line for every flagged result and every 50th problem so the workflow log shows progress.
|
||||
- **Close older discussions**: Configured via `close-older-discussions: true`. Only the latest weekly report remains open.
|
||||
2
.github/workflows/wasm-release.yml
vendored
2
.github/workflows/wasm-release.yml
vendored
|
|
@ -36,7 +36,7 @@ jobs:
|
|||
cp ../../../LICENSE.txt .
|
||||
|
||||
- name: Setup emscripten
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
uses: mymindstorm/setup-emsdk@v16
|
||||
with:
|
||||
no-install: true
|
||||
version: ${{env.EM_VERSION}}
|
||||
|
|
|
|||
2
.github/workflows/wasm.yml
vendored
2
.github/workflows/wasm.yml
vendored
|
|
@ -29,7 +29,7 @@ jobs:
|
|||
node-version: "lts/*"
|
||||
|
||||
- name: Setup emscripten
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
uses: mymindstorm/setup-emsdk@v16
|
||||
with:
|
||||
no-install: true
|
||||
version: ${{env.EM_VERSION}}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,9 @@ network: defaults
|
|||
|
||||
tools:
|
||||
cache-memory: true
|
||||
serena: ["python", "java", "csharp"]
|
||||
github:
|
||||
toolsets: [default]
|
||||
bash: [":*"]
|
||||
glob: {}
|
||||
|
||||
safe-outputs:
|
||||
create-discussion:
|
||||
|
|
|
|||
22
.github/workflows/zipt-code-reviewer.md
vendored
22
.github/workflows/zipt-code-reviewer.md
vendored
|
|
@ -17,8 +17,6 @@ tools:
|
|||
cache-memory: true
|
||||
github:
|
||||
toolsets: [default]
|
||||
view: {}
|
||||
glob: {}
|
||||
edit: {}
|
||||
web-fetch: {}
|
||||
bash:
|
||||
|
|
@ -169,12 +167,10 @@ git diff > /tmp/zipt-improvements.diff
|
|||
cat /tmp/zipt-improvements.diff
|
||||
```
|
||||
|
||||
If no changes were made because no improvements were found or all were too risky, exit gracefully:
|
||||
If no changes were made because no improvements were found or all were too risky, call the `noop` safe-output tool:
|
||||
|
||||
```
|
||||
✅ ZIPT code review complete. No concrete improvements found in this run.
|
||||
Files examined: [list files]
|
||||
ZIPT files compared: [list files]
|
||||
noop: "ZIPT code review complete. No concrete improvements found in this run. Files examined: [list files]. ZIPT files compared: [list files]."
|
||||
```
|
||||
|
||||
## Phase 6: Create GitHub Issue
|
||||
|
|
@ -235,7 +231,12 @@ make test-z3
|
|||
*Generated by ZIPT Code Reviewer agent — comparing Z3 implementation with CEisenhofer/ZIPT@parikh*
|
||||
```
|
||||
|
||||
## Important Guidelines
|
||||
## Important: Always Call a Safe Output Tool
|
||||
|
||||
**You MUST always call at least one safe-output tool before finishing.** Failing to do so is reported as a workflow failure.
|
||||
|
||||
- If you found and applied improvements → call `create_issue`
|
||||
- If ZIPT is unreachable, no improvements were found, or all improvements are out of scope → call `noop` with a brief explanation
|
||||
|
||||
### Scope
|
||||
- **Only** examine the files listed in Phase 1
|
||||
|
|
@ -249,7 +250,12 @@ make test-z3
|
|||
- Prefer small, surgical changes over large refactors
|
||||
|
||||
### Exit Conditions
|
||||
Exit without creating an issue if:
|
||||
Call `noop` (instead of creating an issue) if:
|
||||
- ZIPT repository is unreachable
|
||||
- No concrete, safe improvements can be identified
|
||||
- All identified improvements require architectural changes beyond the scope of a single diff
|
||||
|
||||
Example noop call:
|
||||
```
|
||||
noop: "ZIPT code review complete. No improvements applied: [brief reason, e.g. ZIPT unreachable / no safe changes identified]. Files reviewed: [list]."
|
||||
```
|
||||
|
|
|
|||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -120,3 +120,9 @@ bazel-*
|
|||
.beads
|
||||
build/
|
||||
.z3-agent/
|
||||
.playwright*/
|
||||
.atomic/
|
||||
.deepscan/
|
||||
.deeptest/
|
||||
tptp_test/
|
||||
tptp_benchmarks/
|
||||
|
|
|
|||
|
|
@ -60,6 +60,77 @@ Version 4.17.0
|
|||
https://github.com/Z3Prover/z3/pull/8983
|
||||
- Fix deep API bugs in Z3 C API (null pointer handling, error propagation).
|
||||
https://github.com/Z3Prover/z3/pull/8972
|
||||
- Implement multivariate polynomial factorization via Hensel lifting. Replaces the prior stub
|
||||
implementation (factor_n_sqf_pp) with a working algorithm: evaluate away extra variables to
|
||||
reduce to bivariate, factor the univariate specialization, lift via linear Hensel lifting in
|
||||
Zp[x], and verify the result over Z[x,y]. For more than two variables, bivariate factors are
|
||||
checked against the original polynomial. Thanks to Lev Nachmanson.
|
||||
- Add riscv64 Python wheel builds to nightly and release PyPI publishing.
|
||||
https://github.com/Z3Prover/z3/pull/9153
|
||||
- Fix nlsat clear() crash: reset polynomial cache and root-atom assignments during solver
|
||||
destruction to prevent use-after-free heap corruption. Also fix scoped_numeral_vector copy
|
||||
constructor to read from the source operand instead of uninitialized self.
|
||||
https://github.com/Z3Prover/z3/pull/9150
|
||||
- Fix #9030: in box mode optimization (opt.priority=box), each objective is now optimized
|
||||
independently using push/pop scopes, so adding or removing one objective no longer changes
|
||||
the optimal values of others.
|
||||
- Fix assertion violation in isolate_roots for nested nlsat calls. Fixes #6871.
|
||||
- Fix #9036: expand bounded integer quantifiers in qe-light when Fourier-Motzkin elimination
|
||||
fails due to non-unit coefficients. When all remaining quantified integers have explicit
|
||||
finite bounds and the product of domain sizes is at most 10000, the quantifier is unrolled
|
||||
into an explicit disjunction.
|
||||
- Fix #8023: only skip adding an axiom clause when its satisfying literal is assigned at base
|
||||
level (scope 0). The previous optimization was unsound: literals can be retracted by
|
||||
backtracking, causing the string solver to miss propagations such as indexof(a,s) = -1 when
|
||||
contains(a,s) becomes false after backtracking.
|
||||
- Fix lock contention in theory_diff_logic and theory_dense_diff_logic when using multi-threaded
|
||||
solving (smt.threads > 1). A diagnostic IF_VERBOSE(0,...) call was always acquiring the global
|
||||
verbose mutex, causing catastrophic contention when multiple threads internalized atoms.
|
||||
Fixes #8019.
|
||||
- Fix string solver: move m_fixed insertion after check_long_strings guard to prevent premature
|
||||
marking of string variables with length > 20 as processed.
|
||||
- Fix documentation for Z3_solver_to_dimacs_string: corrected the function name in the API
|
||||
comment. Thanks to Mark DenHoed, https://github.com/Z3Prover/z3/pull/9053
|
||||
- Add global backbones to parallel architecture for smt.threads > 1. Backbone literals learned
|
||||
by any worker thread are broadcast to all others, improving search pruning in the shared search
|
||||
tree. Thanks to Ilana Shapiro.
|
||||
https://github.com/Z3Prover/z3/pull/9343
|
||||
- Terminate on Demand and algorithmic bugfixes in the parallel search tree, including improved
|
||||
worker termination signaling and fixes to node-state management. Thanks to Ilana Shapiro.
|
||||
https://github.com/Z3Prover/z3/pull/9336
|
||||
- Add adaptive growth knobs for Gröbner basis computation under arith.nl.grobner_adaptive.
|
||||
Allows tuning of Gröbner basis expansion rate for better NLA performance. Thanks to Arie.
|
||||
https://github.com/Z3Prover/z3/pull/9390
|
||||
- Improvements to NLA lemmas for better nonlinear arithmetic solving. Thanks to Arie.
|
||||
https://github.com/Z3Prover/z3/pull/9391
|
||||
- Throttle lia2card tactic in QF_NIA preamble to avoid combinatorial explosion on large instances.
|
||||
Thanks to Arie, https://github.com/Z3Prover/z3/pull/9362
|
||||
- Fix smt: reset give-up state when escalating final_check level to prevent solver from
|
||||
incorrectly abandoning solvable instances. Thanks to Lev Nachmanson.
|
||||
https://github.com/Z3Prover/z3/pull/9408
|
||||
- Fix double-free crash in anum by giving anum move semantics to prevent sort-triggered
|
||||
double-free. Thanks to Arie, https://github.com/Z3Prover/z3/pull/9320
|
||||
- Fix lar_term equality operator to correctly compare terms. Thanks to Arie.
|
||||
https://github.com/Z3Prover/z3/pull/9284
|
||||
- Prevent unsound solve-eqs elimination across recursive-function definitions.
|
||||
https://github.com/Z3Prover/z3/pull/9358
|
||||
- Fix inverted logic of is-linear check in solve-eqs, #9311.
|
||||
- Fix #9293: disable elim-uncnstr simplification under quantifiers to prevent unsound
|
||||
eliminations. Also fix #9234, #9309.
|
||||
- Add exception protection for nlsat_tactic and try_for tactic to correctly handle cancellation
|
||||
and ensure robust exception propagation.
|
||||
- Add smt.solve_eqs.linear parameter (default false). When set to true, restricts variable
|
||||
eliminations in solve-eqs to only use linear substitutions, avoiding cross-multiplication
|
||||
of nested substitutions.
|
||||
- Fix null dereference in linearise_multi_pattern: reorder null check before side effect.
|
||||
https://github.com/Z3Prover/z3/pull/9427
|
||||
- Add Go and OCaml API coverage: substitution, AST introspection, Spacer, and Goal completion
|
||||
APIs. https://github.com/Z3Prover/z3/pull/9277
|
||||
- Fix two bugs in Python examples. Thanks to Guangyu (Gary) HU.
|
||||
https://github.com/Z3Prover/z3/pull/9303
|
||||
- Add fold-unfold tactic as an alternative to solve-eqs for variable elimination using
|
||||
fold-unfold transformations. Also exposed as a simplifier.
|
||||
- Handle SIGXCPU (OS timeout) like a regular `-T` timeout. Users should make sure to set the soft limit below the hard one, as in `ulimit -S -t 30 -H -t 31` for a 30s soft limit, so SIGXCPU is delivered before SIGKILL.
|
||||
|
||||
Version 4.16.0
|
||||
==============
|
||||
|
|
|
|||
|
|
@ -262,8 +262,8 @@ FUNCTION(DOTNET_GET_DEPS _DN_PROJECT arguments)
|
|||
ENDIF()
|
||||
|
||||
IF(_DN_NETCOREAPP)
|
||||
SET(_DN_BUILD_OPTIONS -f netcoreapp2.0)
|
||||
SET(_DN_PACK_OPTIONS /p:TargetFrameworks=netcoreapp2.0)
|
||||
SET(_DN_BUILD_OPTIONS -f net8.0)
|
||||
SET(_DN_PACK_OPTIONS /p:TargetFrameworks=net8.0)
|
||||
ELSEIF(UNIX)
|
||||
# Unix builds default to netstandard2.0
|
||||
SET(_DN_BUILD_OPTIONS -f netstandard2.0)
|
||||
|
|
@ -384,7 +384,7 @@ FUNCTION(RUN_DOTNET DOTNET_PROJECT)
|
|||
COMMAND ${DOTNET_EXE} clean ${DOTNET_PROJPATH} ${DOTNET_BUILD_PROPERTIES}
|
||||
COMMAND ${DOTNET_EXE} build --no-restore ${DOTNET_PROJPATH} -c ${DOTNET_CONFIG} ${DOTNET_BUILD_PROPERTIES} ${DOTNET_BUILD_OPTIONS}
|
||||
# XXX tfm
|
||||
COMMAND ${DOTNET_EXE} ${DOTNET_OUTPUT_PATH}/netcoreapp2.0/${DOTNET_PROJNAME}.dll ${DOTNET_ARGUMENTS}
|
||||
COMMAND ${DOTNET_EXE} ${DOTNET_OUTPUT_PATH}/net8.0/${DOTNET_PROJNAME}.dll ${DOTNET_ARGUMENTS}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${DOTNET_PROJNAME}.runtimestamp
|
||||
WORKING_DIRECTORY ${DOTNET_OUTPUT_PATH})
|
||||
ADD_CUSTOM_TARGET(
|
||||
|
|
@ -399,7 +399,7 @@ FUNCTION(TEST_DOTNET DOTNET_PROJECT)
|
|||
IF(WIN32)
|
||||
SET(test_framework_args "")
|
||||
ELSE()
|
||||
SET(test_framework_args -f netcoreapp2.0)
|
||||
SET(test_framework_args -f net8.0)
|
||||
ENDIF()
|
||||
|
||||
ADD_TEST(NAME ${DOTNET_PROJNAME}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ if(UNIX AND NOT APPLE)
|
|||
|
||||
add_custom_target(
|
||||
z3_dotnet_test_manual_copy_assembly_hack ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${z3_dotnet_test_manual_copy_deps} ${PROJECT_BINARY_DIR}/dotnet/netcoreapp2.0/
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${z3_dotnet_test_manual_copy_deps} ${PROJECT_BINARY_DIR}/dotnet/net8.0/
|
||||
# hack the libz3 entry in deps so it's easy enough for dotnet to reach it...
|
||||
COMMAND sed \"s/runtimes\\/.*libz3\\.so/libz3.so/\" -i ${PROJECT_BINARY_DIR}/dotnet/netcoreapp2.0/dotnet.deps.json
|
||||
COMMAND sed \"s/runtimes\\/.*libz3\\.so/libz3.so/\" -i ${PROJECT_BINARY_DIR}/dotnet/net8.0/dotnet.deps.json
|
||||
)
|
||||
|
||||
add_dependencies(z3_dotnet_test_manual_copy_assembly_hack BUILD_dotnet)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ class BinCoverSolver(UserPropagateBase):
|
|||
assert isinstance(value, BitVecNumRef)
|
||||
bin_index = value.as_long()
|
||||
if bin_index >= len(self.bins):
|
||||
return NOne
|
||||
return None
|
||||
return self.bins[bin_index]
|
||||
|
||||
def _add_item2bin(self, item, bin):
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class ComplexExpr:
|
|||
other = _to_complex(other)
|
||||
return And(self.r == other.r, self.i == other.i)
|
||||
|
||||
def __neq__(self, other):
|
||||
def __ne__(self, other):
|
||||
return Not(self.__eq__(other))
|
||||
|
||||
def simplify(self):
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ class Horn2Transitions:
|
|||
pred, inv0 = self.is_body(body)
|
||||
if pred is None:
|
||||
return False
|
||||
if inv0 is None:
|
||||
return False
|
||||
inv1 = self.is_inv(head)
|
||||
if inv1 is None:
|
||||
return False
|
||||
|
|
@ -335,7 +337,7 @@ class MiniIC3:
|
|||
s = self.states[f - 1].solver
|
||||
if unsat == s.check(cube):
|
||||
core = s.unsat_core()
|
||||
if not check_disjoint(self.init, self.prev(And(core))):
|
||||
if len(core) > 0 and check_disjoint(self.init, self.prev(And(core))):
|
||||
return core, f
|
||||
return cube, f
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import heapq
|
|||
import numpy
|
||||
import time
|
||||
import random
|
||||
import sys
|
||||
import copy
|
||||
|
||||
verbose = True
|
||||
|
||||
|
|
@ -78,6 +80,8 @@ class Horn2Transitions:
|
|||
pred, inv0 = self.is_body(body)
|
||||
if pred is None:
|
||||
return False
|
||||
if inv0 is None:
|
||||
return False
|
||||
inv1 = self.is_inv(head)
|
||||
if inv1 is None:
|
||||
return False
|
||||
|
|
@ -349,12 +353,12 @@ class Quip:
|
|||
def next(self, f):
|
||||
if is_seq(f):
|
||||
return [self.next(f1) for f1 in f]
|
||||
return substitute(f, zip(self.x0, self.xn))
|
||||
return substitute(f, list(zip(self.x0, self.xn)))
|
||||
|
||||
def prev(self, f):
|
||||
if is_seq(f):
|
||||
return [self.prev(f1) for f1 in f]
|
||||
return substitute(f, zip(self.xn, self.x0))
|
||||
return substitute(f, list(zip(self.xn, self.x0)))
|
||||
|
||||
def add_solver(self):
|
||||
s = fd_solver()
|
||||
|
|
@ -423,7 +427,8 @@ class Quip:
|
|||
s.push()
|
||||
r = self.reachable.state2cube(state)
|
||||
s.add(And(self.prev(r)))
|
||||
s.add(self.prev(cube))
|
||||
if len(cube) > 0:
|
||||
s.add(And(self.prev(list(cube))))
|
||||
is_sat = s.check()
|
||||
s.pop()
|
||||
if is_sat == sat:
|
||||
|
|
@ -441,7 +446,7 @@ class Quip:
|
|||
s = self.states[f - 1].solver
|
||||
if unsat == s.check(cube):
|
||||
core = s.unsat_core()
|
||||
if self.check_reachable(core):
|
||||
if len(core) > 0 and self.check_reachable(core):
|
||||
return core, f
|
||||
return cube, f
|
||||
|
||||
|
|
@ -454,8 +459,8 @@ class Quip:
|
|||
for state in self.reachable.states:
|
||||
s.push()
|
||||
s.add(And(self.next(self.reachable.state2cube(state))))
|
||||
print self.reachable.state2cube(state)
|
||||
print s.check()
|
||||
print(self.reachable.state2cube(state))
|
||||
print(s.check())
|
||||
s.pop()
|
||||
|
||||
def lemmas(self, level):
|
||||
|
|
@ -553,7 +558,7 @@ class Quip:
|
|||
s.add(self.init)
|
||||
s.add(self.prev(g.cube))
|
||||
# since init is a complete assignment, so g.cube must equal to init in sat solver
|
||||
assert is_sat == s.check()
|
||||
assert sat == s.check()
|
||||
if verbose:
|
||||
print("")
|
||||
return g
|
||||
|
|
@ -564,7 +569,7 @@ class Quip:
|
|||
if r0 is not None:
|
||||
if g.must:
|
||||
if verbose:
|
||||
print ""
|
||||
print("")
|
||||
s = fd_solver()
|
||||
s.add(self.trans)
|
||||
# make it as a concrete reachable state
|
||||
|
|
@ -573,9 +578,16 @@ class Quip:
|
|||
while True:
|
||||
is_sat = s.check(self.next(g.cube))
|
||||
assert is_sat == sat
|
||||
r = self.next(self.project0(s.model()))
|
||||
m = s.model()
|
||||
r = self.next(self.project0(m))
|
||||
r = self.reachable.intersect(self.prev(r))
|
||||
child = QGoal(self.next(r.children()), g, 0, g.must, 0)
|
||||
if r is None:
|
||||
# reachable intersect failed: fall back to the raw
|
||||
# model projection so we still get a concrete
|
||||
# predecessor and avoid crashing on r.children()
|
||||
child = QGoal(self.next(self.project0(m)), g, 0, g.must, 0)
|
||||
else:
|
||||
child = QGoal(self.next(r.children()), g, 0, g.must, 0)
|
||||
g = child
|
||||
if not check_disjoint(self.init, self.prev(g.cube)):
|
||||
# g is init, break the loop
|
||||
|
|
@ -596,7 +608,7 @@ class Quip:
|
|||
for l in self.frames[f_1]:
|
||||
if not l.bad and len(l.cube) > 0 and set(l.cube).issubset(g.cube):
|
||||
cube = l.cube
|
||||
is_sat == unsat
|
||||
is_sat = unsat
|
||||
break
|
||||
f_1 -= 1
|
||||
if cube is None:
|
||||
|
|
@ -707,7 +719,7 @@ def test(file):
|
|||
h2t = Horn2Transitions()
|
||||
h2t.parse(file)
|
||||
if verbose:
|
||||
print("Test file: %s") % file
|
||||
print("Test file: %s" % file)
|
||||
mp = Quip(h2t.init, h2t.trans, h2t.goal, h2t.xs, h2t.inputs, h2t.xns)
|
||||
start_time = time.time()
|
||||
result = mp.run()
|
||||
|
|
@ -744,7 +756,7 @@ def validate(var, result, trans):
|
|||
s.pop()
|
||||
g = g.parent
|
||||
if verbose:
|
||||
print "--- validation succeed ----"
|
||||
print("--- validation succeed ----")
|
||||
return
|
||||
if isinstance(result, ExprRef):
|
||||
inv = result
|
||||
|
|
@ -762,7 +774,7 @@ def validate(var, result, trans):
|
|||
# too many steps to reach invariant
|
||||
if step > 1000:
|
||||
if verbose:
|
||||
print "--- validation failed --"
|
||||
print("--- validation failed --")
|
||||
return
|
||||
if not check_disjoint(var.prev(cube), var.prev(inv)):
|
||||
# reach invariant
|
||||
|
|
@ -773,7 +785,7 @@ def validate(var, result, trans):
|
|||
cube = var.projectN(s.model())
|
||||
s.pop()
|
||||
if verbose:
|
||||
print "--- validation succeed ----"
|
||||
print("--- validation succeed ----")
|
||||
return
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -126,5 +126,3 @@ def init_project_def():
|
|||
add_ml_example('ml_example', 'ml')
|
||||
add_z3py_example('py_example', 'python')
|
||||
return API_files
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2314,7 +2314,7 @@ class DotNetExampleComponent(ExampleComponent):
|
|||
dotnet_proj_str = r"""<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<PlatformTarget>%s</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -129,7 +129,6 @@ extern "C" {
|
|||
Z3_TRY;
|
||||
LOG_Z3_mk_rec_func_decl(c, s, domain_size, domain, range);
|
||||
RESET_ERROR_CODE();
|
||||
//
|
||||
recfun::promise_def def =
|
||||
mk_c(c)->recfun().get_plugin().mk_def(
|
||||
to_symbol(s), domain_size, to_sorts(domain), to_sort(range), false);
|
||||
|
|
@ -1088,407 +1087,425 @@ extern "C" {
|
|||
Z3_CATCH_RETURN("");
|
||||
}
|
||||
|
||||
// Helper functions to reduce instruction cache pressure in Z3_get_decl_kind.
|
||||
// Each theory gets its own function to avoid loading the entire switch table.
|
||||
|
||||
static Z3_decl_kind get_decl_kind_basic(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_TRUE: return Z3_OP_TRUE;
|
||||
case OP_FALSE: return Z3_OP_FALSE;
|
||||
case OP_EQ: return Z3_OP_EQ;
|
||||
case OP_DISTINCT: return Z3_OP_DISTINCT;
|
||||
case OP_ITE: return Z3_OP_ITE;
|
||||
case OP_AND: return Z3_OP_AND;
|
||||
case OP_OR: return Z3_OP_OR;
|
||||
case OP_XOR: return Z3_OP_XOR;
|
||||
case OP_NOT: return Z3_OP_NOT;
|
||||
case OP_IMPLIES: return Z3_OP_IMPLIES;
|
||||
case OP_OEQ: return Z3_OP_OEQ;
|
||||
case PR_UNDEF: return Z3_OP_PR_UNDEF;
|
||||
case PR_TRUE: return Z3_OP_PR_TRUE;
|
||||
case PR_ASSERTED: return Z3_OP_PR_ASSERTED;
|
||||
case PR_GOAL: return Z3_OP_PR_GOAL;
|
||||
case PR_MODUS_PONENS: return Z3_OP_PR_MODUS_PONENS;
|
||||
case PR_REFLEXIVITY: return Z3_OP_PR_REFLEXIVITY;
|
||||
case PR_SYMMETRY: return Z3_OP_PR_SYMMETRY;
|
||||
case PR_TRANSITIVITY: return Z3_OP_PR_TRANSITIVITY;
|
||||
case PR_TRANSITIVITY_STAR: return Z3_OP_PR_TRANSITIVITY_STAR;
|
||||
case PR_MONOTONICITY: return Z3_OP_PR_MONOTONICITY;
|
||||
case PR_QUANT_INTRO: return Z3_OP_PR_QUANT_INTRO;
|
||||
case PR_BIND: return Z3_OP_PR_BIND;
|
||||
case PR_DISTRIBUTIVITY: return Z3_OP_PR_DISTRIBUTIVITY;
|
||||
case PR_AND_ELIM: return Z3_OP_PR_AND_ELIM;
|
||||
case PR_NOT_OR_ELIM: return Z3_OP_PR_NOT_OR_ELIM;
|
||||
case PR_REWRITE: return Z3_OP_PR_REWRITE;
|
||||
case PR_REWRITE_STAR: return Z3_OP_PR_REWRITE_STAR;
|
||||
case PR_PULL_QUANT: return Z3_OP_PR_PULL_QUANT;
|
||||
case PR_PUSH_QUANT: return Z3_OP_PR_PUSH_QUANT;
|
||||
case PR_ELIM_UNUSED_VARS: return Z3_OP_PR_ELIM_UNUSED_VARS;
|
||||
case PR_DER: return Z3_OP_PR_DER;
|
||||
case PR_QUANT_INST: return Z3_OP_PR_QUANT_INST;
|
||||
case PR_HYPOTHESIS: return Z3_OP_PR_HYPOTHESIS;
|
||||
case PR_LEMMA: return Z3_OP_PR_LEMMA;
|
||||
case PR_UNIT_RESOLUTION: return Z3_OP_PR_UNIT_RESOLUTION;
|
||||
case PR_IFF_TRUE: return Z3_OP_PR_IFF_TRUE;
|
||||
case PR_IFF_FALSE: return Z3_OP_PR_IFF_FALSE;
|
||||
case PR_COMMUTATIVITY: return Z3_OP_PR_COMMUTATIVITY;
|
||||
case PR_DEF_AXIOM: return Z3_OP_PR_DEF_AXIOM;
|
||||
case PR_ASSUMPTION_ADD: return Z3_OP_PR_ASSUMPTION_ADD;
|
||||
case PR_LEMMA_ADD: return Z3_OP_PR_LEMMA_ADD;
|
||||
case PR_REDUNDANT_DEL: return Z3_OP_PR_REDUNDANT_DEL;
|
||||
case PR_CLAUSE_TRAIL: return Z3_OP_PR_CLAUSE_TRAIL;
|
||||
case PR_DEF_INTRO: return Z3_OP_PR_DEF_INTRO;
|
||||
case PR_APPLY_DEF: return Z3_OP_PR_APPLY_DEF;
|
||||
case PR_IFF_OEQ: return Z3_OP_PR_IFF_OEQ;
|
||||
case PR_NNF_POS: return Z3_OP_PR_NNF_POS;
|
||||
case PR_NNF_NEG: return Z3_OP_PR_NNF_NEG;
|
||||
case PR_SKOLEMIZE: return Z3_OP_PR_SKOLEMIZE;
|
||||
case PR_MODUS_PONENS_OEQ: return Z3_OP_PR_MODUS_PONENS_OEQ;
|
||||
case PR_TH_LEMMA: return Z3_OP_PR_TH_LEMMA;
|
||||
case PR_HYPER_RESOLVE: return Z3_OP_PR_HYPER_RESOLVE;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_arith(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_NUM: return Z3_OP_ANUM;
|
||||
case OP_IRRATIONAL_ALGEBRAIC_NUM: return Z3_OP_AGNUM;
|
||||
case OP_LE: return Z3_OP_LE;
|
||||
case OP_GE: return Z3_OP_GE;
|
||||
case OP_LT: return Z3_OP_LT;
|
||||
case OP_GT: return Z3_OP_GT;
|
||||
case OP_ADD: return Z3_OP_ADD;
|
||||
case OP_SUB: return Z3_OP_SUB;
|
||||
case OP_UMINUS: return Z3_OP_UMINUS;
|
||||
case OP_MUL: return Z3_OP_MUL;
|
||||
case OP_DIV: return Z3_OP_DIV;
|
||||
case OP_IDIV: return Z3_OP_IDIV;
|
||||
case OP_REM: return Z3_OP_REM;
|
||||
case OP_MOD: return Z3_OP_MOD;
|
||||
case OP_POWER: return Z3_OP_POWER;
|
||||
case OP_ABS: return Z3_OP_ABS;
|
||||
case OP_TO_REAL: return Z3_OP_TO_REAL;
|
||||
case OP_TO_INT: return Z3_OP_TO_INT;
|
||||
case OP_IS_INT: return Z3_OP_IS_INT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_array(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_STORE: return Z3_OP_STORE;
|
||||
case OP_SELECT: return Z3_OP_SELECT;
|
||||
case OP_CONST_ARRAY: return Z3_OP_CONST_ARRAY;
|
||||
case OP_ARRAY_DEFAULT: return Z3_OP_ARRAY_DEFAULT;
|
||||
case OP_ARRAY_MAP: return Z3_OP_ARRAY_MAP;
|
||||
case OP_SET_UNION: return Z3_OP_SET_UNION;
|
||||
case OP_SET_INTERSECT: return Z3_OP_SET_INTERSECT;
|
||||
case OP_SET_DIFFERENCE: return Z3_OP_SET_DIFFERENCE;
|
||||
case OP_SET_COMPLEMENT: return Z3_OP_SET_COMPLEMENT;
|
||||
case OP_SET_SUBSET: return Z3_OP_SET_SUBSET;
|
||||
case OP_AS_ARRAY: return Z3_OP_AS_ARRAY;
|
||||
case OP_ARRAY_EXT: return Z3_OP_ARRAY_EXT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_special_relations(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO;
|
||||
case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO;
|
||||
case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO;
|
||||
case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO;
|
||||
case OP_SPECIAL_RELATION_TC : return Z3_OP_SPECIAL_RELATION_TC;
|
||||
default: UNREACHABLE(); return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_bv(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_BV_NUM: return Z3_OP_BNUM;
|
||||
case OP_BIT1: return Z3_OP_BIT1;
|
||||
case OP_BIT0: return Z3_OP_BIT0;
|
||||
case OP_BNEG: return Z3_OP_BNEG;
|
||||
case OP_BADD: return Z3_OP_BADD;
|
||||
case OP_BSUB: return Z3_OP_BSUB;
|
||||
case OP_BMUL: return Z3_OP_BMUL;
|
||||
case OP_BSDIV: return Z3_OP_BSDIV;
|
||||
case OP_BUDIV: return Z3_OP_BUDIV;
|
||||
case OP_BSREM: return Z3_OP_BSREM;
|
||||
case OP_BUREM: return Z3_OP_BUREM;
|
||||
case OP_BSMOD: return Z3_OP_BSMOD;
|
||||
case OP_BSDIV0: return Z3_OP_BSDIV0;
|
||||
case OP_BUDIV0: return Z3_OP_BUDIV0;
|
||||
case OP_BSREM0: return Z3_OP_BSREM0;
|
||||
case OP_BUREM0: return Z3_OP_BUREM0;
|
||||
case OP_BSMOD0: return Z3_OP_BSMOD0;
|
||||
case OP_ULEQ: return Z3_OP_ULEQ;
|
||||
case OP_SLEQ: return Z3_OP_SLEQ;
|
||||
case OP_UGEQ: return Z3_OP_UGEQ;
|
||||
case OP_SGEQ: return Z3_OP_SGEQ;
|
||||
case OP_ULT: return Z3_OP_ULT;
|
||||
case OP_SLT: return Z3_OP_SLT;
|
||||
case OP_UGT: return Z3_OP_UGT;
|
||||
case OP_SGT: return Z3_OP_SGT;
|
||||
case OP_BAND: return Z3_OP_BAND;
|
||||
case OP_BOR: return Z3_OP_BOR;
|
||||
case OP_BNOT: return Z3_OP_BNOT;
|
||||
case OP_BXOR: return Z3_OP_BXOR;
|
||||
case OP_BNAND: return Z3_OP_BNAND;
|
||||
case OP_BNOR: return Z3_OP_BNOR;
|
||||
case OP_BXNOR: return Z3_OP_BXNOR;
|
||||
case OP_CONCAT: return Z3_OP_CONCAT;
|
||||
case OP_SIGN_EXT: return Z3_OP_SIGN_EXT;
|
||||
case OP_ZERO_EXT: return Z3_OP_ZERO_EXT;
|
||||
case OP_EXTRACT: return Z3_OP_EXTRACT;
|
||||
case OP_REPEAT: return Z3_OP_REPEAT;
|
||||
case OP_BREDOR: return Z3_OP_BREDOR;
|
||||
case OP_BREDAND: return Z3_OP_BREDAND;
|
||||
case OP_BCOMP: return Z3_OP_BCOMP;
|
||||
case OP_BSHL: return Z3_OP_BSHL;
|
||||
case OP_BLSHR: return Z3_OP_BLSHR;
|
||||
case OP_BASHR: return Z3_OP_BASHR;
|
||||
case OP_ROTATE_LEFT: return Z3_OP_ROTATE_LEFT;
|
||||
case OP_ROTATE_RIGHT: return Z3_OP_ROTATE_RIGHT;
|
||||
case OP_EXT_ROTATE_LEFT: return Z3_OP_EXT_ROTATE_LEFT;
|
||||
case OP_EXT_ROTATE_RIGHT: return Z3_OP_EXT_ROTATE_RIGHT;
|
||||
case OP_INT2BV: return Z3_OP_INT2BV;
|
||||
case OP_UBV2INT: return Z3_OP_BV2INT;
|
||||
case OP_SBV2INT: return Z3_OP_SBV2INT;
|
||||
case OP_CARRY: return Z3_OP_CARRY;
|
||||
case OP_XOR3: return Z3_OP_XOR3;
|
||||
case OP_BIT2BOOL: return Z3_OP_BIT2BOOL;
|
||||
case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL;
|
||||
case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL;
|
||||
case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL;
|
||||
case OP_BSDIV_I: return Z3_OP_BSDIV_I;
|
||||
case OP_BUDIV_I: return Z3_OP_BUDIV_I;
|
||||
case OP_BSREM_I: return Z3_OP_BSREM_I;
|
||||
case OP_BUREM_I: return Z3_OP_BUREM_I;
|
||||
case OP_BSMOD_I: return Z3_OP_BSMOD_I;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_dt(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR;
|
||||
case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER;
|
||||
case OP_DT_IS: return Z3_OP_DT_IS;
|
||||
case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR;
|
||||
case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_datalog(decl_kind k) {
|
||||
switch(k) {
|
||||
case datalog::OP_RA_STORE: return Z3_OP_RA_STORE;
|
||||
case datalog::OP_RA_EMPTY: return Z3_OP_RA_EMPTY;
|
||||
case datalog::OP_RA_IS_EMPTY: return Z3_OP_RA_IS_EMPTY;
|
||||
case datalog::OP_RA_JOIN: return Z3_OP_RA_JOIN;
|
||||
case datalog::OP_RA_UNION: return Z3_OP_RA_UNION;
|
||||
case datalog::OP_RA_WIDEN: return Z3_OP_RA_WIDEN;
|
||||
case datalog::OP_RA_PROJECT: return Z3_OP_RA_PROJECT;
|
||||
case datalog::OP_RA_FILTER: return Z3_OP_RA_FILTER;
|
||||
case datalog::OP_RA_NEGATION_FILTER: return Z3_OP_RA_NEGATION_FILTER;
|
||||
case datalog::OP_RA_RENAME: return Z3_OP_RA_RENAME;
|
||||
case datalog::OP_RA_COMPLEMENT: return Z3_OP_RA_COMPLEMENT;
|
||||
case datalog::OP_RA_SELECT: return Z3_OP_RA_SELECT;
|
||||
case datalog::OP_RA_CLONE: return Z3_OP_RA_CLONE;
|
||||
case datalog::OP_DL_CONSTANT: return Z3_OP_FD_CONSTANT;
|
||||
case datalog::OP_DL_LT: return Z3_OP_FD_LT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_seq(decl_kind k) {
|
||||
switch (k) {
|
||||
case OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT;
|
||||
case OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY;
|
||||
case OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS;
|
||||
case OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT;
|
||||
case OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE;
|
||||
case OP_SEQ_REPLACE_RE: return Z3_OP_SEQ_REPLACE_RE;
|
||||
case OP_SEQ_REPLACE_RE_ALL: return Z3_OP_SEQ_REPLACE_RE_ALL;
|
||||
case OP_SEQ_REPLACE_ALL: return Z3_OP_SEQ_REPLACE_ALL;
|
||||
case OP_SEQ_AT: return Z3_OP_SEQ_AT;
|
||||
case OP_SEQ_NTH: return Z3_OP_SEQ_NTH;
|
||||
case OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX;
|
||||
case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE;
|
||||
case OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE;
|
||||
case OP_SEQ_MAP: return Z3_OP_SEQ_MAP;
|
||||
case OP_SEQ_MAPI: return Z3_OP_SEQ_MAPI;
|
||||
case OP_SEQ_FOLDL: return Z3_OP_SEQ_FOLDL;
|
||||
case OP_SEQ_FOLDLI: return Z3_OP_SEQ_FOLDLI;
|
||||
case _OP_STRING_STRREPL: return Z3_OP_SEQ_REPLACE;
|
||||
case _OP_STRING_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case _OP_STRING_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case _OP_STRING_STRCTN: return Z3_OP_SEQ_CONTAINS;
|
||||
case _OP_STRING_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case _OP_STRING_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case _OP_STRING_IN_REGEXP: return Z3_OP_SEQ_IN_RE;
|
||||
case _OP_STRING_TO_REGEXP: return Z3_OP_SEQ_TO_RE;
|
||||
case _OP_STRING_CHARAT: return Z3_OP_SEQ_AT;
|
||||
case _OP_STRING_SUBSTR: return Z3_OP_SEQ_EXTRACT;
|
||||
case _OP_STRING_STRIDOF: return Z3_OP_SEQ_INDEX;
|
||||
case _OP_REGEXP_EMPTY: return Z3_OP_RE_EMPTY_SET;
|
||||
case _OP_REGEXP_FULL_CHAR: return Z3_OP_RE_FULL_SET;
|
||||
case OP_STRING_STOI: return Z3_OP_STR_TO_INT;
|
||||
case OP_STRING_ITOS: return Z3_OP_INT_TO_STR;
|
||||
case OP_STRING_TO_CODE: return Z3_OP_STR_TO_CODE;
|
||||
case OP_STRING_FROM_CODE: return Z3_OP_STR_FROM_CODE;
|
||||
case OP_STRING_UBVTOS: return Z3_OP_UBV_TO_STR;
|
||||
case OP_STRING_SBVTOS: return Z3_OP_SBV_TO_STR;
|
||||
case OP_STRING_LT: return Z3_OP_STRING_LT;
|
||||
case OP_STRING_LE: return Z3_OP_STRING_LE;
|
||||
case OP_RE_PLUS: return Z3_OP_RE_PLUS;
|
||||
case OP_RE_STAR: return Z3_OP_RE_STAR;
|
||||
case OP_RE_OPTION: return Z3_OP_RE_OPTION;
|
||||
case OP_RE_RANGE: return Z3_OP_RE_RANGE;
|
||||
case OP_RE_CONCAT: return Z3_OP_RE_CONCAT;
|
||||
case OP_RE_UNION: return Z3_OP_RE_UNION;
|
||||
case OP_RE_DIFF: return Z3_OP_RE_DIFF;
|
||||
case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT;
|
||||
case OP_RE_LOOP: return Z3_OP_RE_LOOP;
|
||||
case OP_RE_POWER: return Z3_OP_RE_POWER;
|
||||
case OP_RE_COMPLEMENT: return Z3_OP_RE_COMPLEMENT;
|
||||
case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET;
|
||||
case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET;
|
||||
case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_CHAR_SET;
|
||||
case OP_RE_OF_PRED: return Z3_OP_RE_OF_PRED;
|
||||
case OP_RE_REVERSE: return Z3_OP_RE_REVERSE;
|
||||
case OP_RE_DERIVATIVE: return Z3_OP_RE_DERIVATIVE;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_char(decl_kind k) {
|
||||
switch (k) {
|
||||
case OP_CHAR_CONST: return Z3_OP_CHAR_CONST;
|
||||
case OP_CHAR_LE: return Z3_OP_CHAR_LE;
|
||||
case OP_CHAR_TO_INT: return Z3_OP_CHAR_TO_INT;
|
||||
case OP_CHAR_TO_BV: return Z3_OP_CHAR_TO_BV;
|
||||
case OP_CHAR_FROM_BV: return Z3_OP_CHAR_FROM_BV;
|
||||
case OP_CHAR_IS_DIGIT: return Z3_OP_CHAR_IS_DIGIT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_fpa(decl_kind k) {
|
||||
switch (k) {
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN;
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_AWAY: return Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY;
|
||||
case OP_FPA_RM_TOWARD_POSITIVE: return Z3_OP_FPA_RM_TOWARD_POSITIVE;
|
||||
case OP_FPA_RM_TOWARD_NEGATIVE: return Z3_OP_FPA_RM_TOWARD_NEGATIVE;
|
||||
case OP_FPA_RM_TOWARD_ZERO: return Z3_OP_FPA_RM_TOWARD_ZERO;
|
||||
case OP_FPA_NUM: return Z3_OP_FPA_NUM;
|
||||
case OP_FPA_PLUS_INF: return Z3_OP_FPA_PLUS_INF;
|
||||
case OP_FPA_MINUS_INF: return Z3_OP_FPA_MINUS_INF;
|
||||
case OP_FPA_NAN: return Z3_OP_FPA_NAN;
|
||||
case OP_FPA_MINUS_ZERO: return Z3_OP_FPA_MINUS_ZERO;
|
||||
case OP_FPA_PLUS_ZERO: return Z3_OP_FPA_PLUS_ZERO;
|
||||
case OP_FPA_ADD: return Z3_OP_FPA_ADD;
|
||||
case OP_FPA_SUB: return Z3_OP_FPA_SUB;
|
||||
case OP_FPA_NEG: return Z3_OP_FPA_NEG;
|
||||
case OP_FPA_MUL: return Z3_OP_FPA_MUL;
|
||||
case OP_FPA_DIV: return Z3_OP_FPA_DIV;
|
||||
case OP_FPA_REM: return Z3_OP_FPA_REM;
|
||||
case OP_FPA_ABS: return Z3_OP_FPA_ABS;
|
||||
case OP_FPA_MIN: return Z3_OP_FPA_MIN;
|
||||
case OP_FPA_MAX: return Z3_OP_FPA_MAX;
|
||||
case OP_FPA_FMA: return Z3_OP_FPA_FMA;
|
||||
case OP_FPA_SQRT: return Z3_OP_FPA_SQRT;
|
||||
case OP_FPA_EQ: return Z3_OP_FPA_EQ;
|
||||
case OP_FPA_ROUND_TO_INTEGRAL: return Z3_OP_FPA_ROUND_TO_INTEGRAL;
|
||||
case OP_FPA_LT: return Z3_OP_FPA_LT;
|
||||
case OP_FPA_GT: return Z3_OP_FPA_GT;
|
||||
case OP_FPA_LE: return Z3_OP_FPA_LE;
|
||||
case OP_FPA_GE: return Z3_OP_FPA_GE;
|
||||
case OP_FPA_IS_NAN: return Z3_OP_FPA_IS_NAN;
|
||||
case OP_FPA_IS_INF: return Z3_OP_FPA_IS_INF;
|
||||
case OP_FPA_IS_ZERO: return Z3_OP_FPA_IS_ZERO;
|
||||
case OP_FPA_IS_NORMAL: return Z3_OP_FPA_IS_NORMAL;
|
||||
case OP_FPA_IS_SUBNORMAL: return Z3_OP_FPA_IS_SUBNORMAL;
|
||||
case OP_FPA_IS_NEGATIVE: return Z3_OP_FPA_IS_NEGATIVE;
|
||||
case OP_FPA_IS_POSITIVE: return Z3_OP_FPA_IS_POSITIVE;
|
||||
case OP_FPA_FP: return Z3_OP_FPA_FP;
|
||||
case OP_FPA_TO_FP: return Z3_OP_FPA_TO_FP;
|
||||
case OP_FPA_TO_FP_UNSIGNED: return Z3_OP_FPA_TO_FP_UNSIGNED;
|
||||
case OP_FPA_TO_UBV: return Z3_OP_FPA_TO_UBV;
|
||||
case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV;
|
||||
case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL;
|
||||
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
|
||||
case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP;
|
||||
case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_label(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_LABEL: return Z3_OP_LABEL;
|
||||
case OP_LABEL_LIT: return Z3_OP_LABEL_LIT;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_pb(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_PB_LE: return Z3_OP_PB_LE;
|
||||
case OP_PB_GE: return Z3_OP_PB_GE;
|
||||
case OP_PB_EQ: return Z3_OP_PB_EQ;
|
||||
case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST;
|
||||
case OP_AT_LEAST_K: return Z3_OP_PB_AT_LEAST;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static Z3_decl_kind get_decl_kind_finite_set(decl_kind k) {
|
||||
switch(k) {
|
||||
case OP_FINITE_SET_EMPTY: return Z3_OP_FINITE_SET_EMPTY;
|
||||
case OP_FINITE_SET_SINGLETON: return Z3_OP_FINITE_SET_SINGLETON;
|
||||
case OP_FINITE_SET_UNION: return Z3_OP_FINITE_SET_UNION;
|
||||
case OP_FINITE_SET_INTERSECT: return Z3_OP_FINITE_SET_INTERSECT;
|
||||
case OP_FINITE_SET_DIFFERENCE: return Z3_OP_FINITE_SET_DIFFERENCE;
|
||||
case OP_FINITE_SET_IN: return Z3_OP_FINITE_SET_IN;
|
||||
case OP_FINITE_SET_SIZE: return Z3_OP_FINITE_SET_SIZE;
|
||||
case OP_FINITE_SET_SUBSET: return Z3_OP_FINITE_SET_SUBSET;
|
||||
case OP_FINITE_SET_MAP: return Z3_OP_FINITE_SET_MAP;
|
||||
case OP_FINITE_SET_FILTER: return Z3_OP_FINITE_SET_FILTER;
|
||||
case OP_FINITE_SET_RANGE: return Z3_OP_FINITE_SET_RANGE;
|
||||
case OP_FINITE_SET_EXT: return Z3_OP_FINITE_SET_EXT;
|
||||
case OP_FINITE_SET_MAP_INVERSE: return Z3_OP_FINITE_SET_MAP_INVERSE;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
Z3_decl_kind Z3_API Z3_get_decl_kind(Z3_context c, Z3_func_decl d) {
|
||||
Z3_TRY;
|
||||
LOG_Z3_get_decl_kind(c, d);
|
||||
RESET_ERROR_CODE();
|
||||
func_decl* _d = to_func_decl(d);
|
||||
|
||||
if (d == nullptr || null_family_id == _d->get_family_id()) {
|
||||
if (d == nullptr || null_family_id == _d->get_family_id())
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
}
|
||||
if (mk_c(c)->get_basic_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_TRUE: return Z3_OP_TRUE;
|
||||
case OP_FALSE: return Z3_OP_FALSE;
|
||||
case OP_EQ: return Z3_OP_EQ;
|
||||
case OP_DISTINCT: return Z3_OP_DISTINCT;
|
||||
case OP_ITE: return Z3_OP_ITE;
|
||||
case OP_AND: return Z3_OP_AND;
|
||||
case OP_OR: return Z3_OP_OR;
|
||||
case OP_XOR: return Z3_OP_XOR;
|
||||
case OP_NOT: return Z3_OP_NOT;
|
||||
case OP_IMPLIES: return Z3_OP_IMPLIES;
|
||||
case OP_OEQ: return Z3_OP_OEQ;
|
||||
|
||||
case PR_UNDEF: return Z3_OP_PR_UNDEF;
|
||||
case PR_TRUE: return Z3_OP_PR_TRUE;
|
||||
case PR_ASSERTED: return Z3_OP_PR_ASSERTED;
|
||||
case PR_GOAL: return Z3_OP_PR_GOAL;
|
||||
case PR_MODUS_PONENS: return Z3_OP_PR_MODUS_PONENS;
|
||||
case PR_REFLEXIVITY: return Z3_OP_PR_REFLEXIVITY;
|
||||
case PR_SYMMETRY: return Z3_OP_PR_SYMMETRY;
|
||||
case PR_TRANSITIVITY: return Z3_OP_PR_TRANSITIVITY;
|
||||
case PR_TRANSITIVITY_STAR: return Z3_OP_PR_TRANSITIVITY_STAR;
|
||||
case PR_MONOTONICITY: return Z3_OP_PR_MONOTONICITY;
|
||||
case PR_QUANT_INTRO: return Z3_OP_PR_QUANT_INTRO;
|
||||
case PR_BIND: return Z3_OP_PR_BIND;
|
||||
case PR_DISTRIBUTIVITY: return Z3_OP_PR_DISTRIBUTIVITY;
|
||||
case PR_AND_ELIM: return Z3_OP_PR_AND_ELIM;
|
||||
case PR_NOT_OR_ELIM: return Z3_OP_PR_NOT_OR_ELIM;
|
||||
case PR_REWRITE: return Z3_OP_PR_REWRITE;
|
||||
case PR_REWRITE_STAR: return Z3_OP_PR_REWRITE_STAR;
|
||||
case PR_PULL_QUANT: return Z3_OP_PR_PULL_QUANT;
|
||||
case PR_PUSH_QUANT: return Z3_OP_PR_PUSH_QUANT;
|
||||
case PR_ELIM_UNUSED_VARS: return Z3_OP_PR_ELIM_UNUSED_VARS;
|
||||
case PR_DER: return Z3_OP_PR_DER;
|
||||
case PR_QUANT_INST: return Z3_OP_PR_QUANT_INST;
|
||||
case PR_HYPOTHESIS: return Z3_OP_PR_HYPOTHESIS;
|
||||
case PR_LEMMA: return Z3_OP_PR_LEMMA;
|
||||
case PR_UNIT_RESOLUTION: return Z3_OP_PR_UNIT_RESOLUTION;
|
||||
case PR_IFF_TRUE: return Z3_OP_PR_IFF_TRUE;
|
||||
case PR_IFF_FALSE: return Z3_OP_PR_IFF_FALSE;
|
||||
case PR_COMMUTATIVITY: return Z3_OP_PR_COMMUTATIVITY;
|
||||
case PR_DEF_AXIOM: return Z3_OP_PR_DEF_AXIOM;
|
||||
case PR_ASSUMPTION_ADD: return Z3_OP_PR_ASSUMPTION_ADD;
|
||||
case PR_LEMMA_ADD: return Z3_OP_PR_LEMMA_ADD;
|
||||
case PR_REDUNDANT_DEL: return Z3_OP_PR_REDUNDANT_DEL;
|
||||
case PR_CLAUSE_TRAIL: return Z3_OP_PR_CLAUSE_TRAIL;
|
||||
case PR_DEF_INTRO: return Z3_OP_PR_DEF_INTRO;
|
||||
case PR_APPLY_DEF: return Z3_OP_PR_APPLY_DEF;
|
||||
case PR_IFF_OEQ: return Z3_OP_PR_IFF_OEQ;
|
||||
case PR_NNF_POS: return Z3_OP_PR_NNF_POS;
|
||||
case PR_NNF_NEG: return Z3_OP_PR_NNF_NEG;
|
||||
case PR_SKOLEMIZE: return Z3_OP_PR_SKOLEMIZE;
|
||||
case PR_MODUS_PONENS_OEQ: return Z3_OP_PR_MODUS_PONENS_OEQ;
|
||||
case PR_TH_LEMMA: return Z3_OP_PR_TH_LEMMA;
|
||||
case PR_HYPER_RESOLVE: return Z3_OP_PR_HYPER_RESOLVE;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_arith_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_NUM: return Z3_OP_ANUM;
|
||||
case OP_IRRATIONAL_ALGEBRAIC_NUM: return Z3_OP_AGNUM;
|
||||
case OP_LE: return Z3_OP_LE;
|
||||
case OP_GE: return Z3_OP_GE;
|
||||
case OP_LT: return Z3_OP_LT;
|
||||
case OP_GT: return Z3_OP_GT;
|
||||
case OP_ADD: return Z3_OP_ADD;
|
||||
case OP_SUB: return Z3_OP_SUB;
|
||||
case OP_UMINUS: return Z3_OP_UMINUS;
|
||||
case OP_MUL: return Z3_OP_MUL;
|
||||
case OP_DIV: return Z3_OP_DIV;
|
||||
case OP_IDIV: return Z3_OP_IDIV;
|
||||
case OP_REM: return Z3_OP_REM;
|
||||
case OP_MOD: return Z3_OP_MOD;
|
||||
case OP_POWER: return Z3_OP_POWER;
|
||||
case OP_ABS: return Z3_OP_ABS;
|
||||
case OP_TO_REAL: return Z3_OP_TO_REAL;
|
||||
case OP_TO_INT: return Z3_OP_TO_INT;
|
||||
case OP_IS_INT: return Z3_OP_IS_INT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_array_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_STORE: return Z3_OP_STORE;
|
||||
case OP_SELECT: return Z3_OP_SELECT;
|
||||
case OP_CONST_ARRAY: return Z3_OP_CONST_ARRAY;
|
||||
case OP_ARRAY_DEFAULT: return Z3_OP_ARRAY_DEFAULT;
|
||||
case OP_ARRAY_MAP: return Z3_OP_ARRAY_MAP;
|
||||
case OP_SET_UNION: return Z3_OP_SET_UNION;
|
||||
case OP_SET_INTERSECT: return Z3_OP_SET_INTERSECT;
|
||||
case OP_SET_DIFFERENCE: return Z3_OP_SET_DIFFERENCE;
|
||||
case OP_SET_COMPLEMENT: return Z3_OP_SET_COMPLEMENT;
|
||||
case OP_SET_SUBSET: return Z3_OP_SET_SUBSET;
|
||||
case OP_AS_ARRAY: return Z3_OP_AS_ARRAY;
|
||||
case OP_ARRAY_EXT: return Z3_OP_ARRAY_EXT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
family_id fid = _d->get_family_id();
|
||||
decl_kind k = _d->get_decl_kind();
|
||||
|
||||
if (mk_c(c)->get_special_relations_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_SPECIAL_RELATION_LO : return Z3_OP_SPECIAL_RELATION_LO;
|
||||
case OP_SPECIAL_RELATION_PO : return Z3_OP_SPECIAL_RELATION_PO;
|
||||
case OP_SPECIAL_RELATION_PLO: return Z3_OP_SPECIAL_RELATION_PLO;
|
||||
case OP_SPECIAL_RELATION_TO : return Z3_OP_SPECIAL_RELATION_TO;
|
||||
case OP_SPECIAL_RELATION_TC : return Z3_OP_SPECIAL_RELATION_TC;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mk_c(c)->get_bv_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_BV_NUM: return Z3_OP_BNUM;
|
||||
case OP_BIT1: return Z3_OP_BIT1;
|
||||
case OP_BIT0: return Z3_OP_BIT0;
|
||||
case OP_BNEG: return Z3_OP_BNEG;
|
||||
case OP_BADD: return Z3_OP_BADD;
|
||||
case OP_BSUB: return Z3_OP_BSUB;
|
||||
case OP_BMUL: return Z3_OP_BMUL;
|
||||
case OP_BSDIV: return Z3_OP_BSDIV;
|
||||
case OP_BUDIV: return Z3_OP_BUDIV;
|
||||
case OP_BSREM: return Z3_OP_BSREM;
|
||||
case OP_BUREM: return Z3_OP_BUREM;
|
||||
case OP_BSMOD: return Z3_OP_BSMOD;
|
||||
case OP_BSDIV0: return Z3_OP_BSDIV0;
|
||||
case OP_BUDIV0: return Z3_OP_BUDIV0;
|
||||
case OP_BSREM0: return Z3_OP_BSREM0;
|
||||
case OP_BUREM0: return Z3_OP_BUREM0;
|
||||
case OP_BSMOD0: return Z3_OP_BSMOD0;
|
||||
case OP_ULEQ: return Z3_OP_ULEQ;
|
||||
case OP_SLEQ: return Z3_OP_SLEQ;
|
||||
case OP_UGEQ: return Z3_OP_UGEQ;
|
||||
case OP_SGEQ: return Z3_OP_SGEQ;
|
||||
case OP_ULT: return Z3_OP_ULT;
|
||||
case OP_SLT: return Z3_OP_SLT;
|
||||
case OP_UGT: return Z3_OP_UGT;
|
||||
case OP_SGT: return Z3_OP_SGT;
|
||||
case OP_BAND: return Z3_OP_BAND;
|
||||
case OP_BOR: return Z3_OP_BOR;
|
||||
case OP_BNOT: return Z3_OP_BNOT;
|
||||
case OP_BXOR: return Z3_OP_BXOR;
|
||||
case OP_BNAND: return Z3_OP_BNAND;
|
||||
case OP_BNOR: return Z3_OP_BNOR;
|
||||
case OP_BXNOR: return Z3_OP_BXNOR;
|
||||
case OP_CONCAT: return Z3_OP_CONCAT;
|
||||
case OP_SIGN_EXT: return Z3_OP_SIGN_EXT;
|
||||
case OP_ZERO_EXT: return Z3_OP_ZERO_EXT;
|
||||
case OP_EXTRACT: return Z3_OP_EXTRACT;
|
||||
case OP_REPEAT: return Z3_OP_REPEAT;
|
||||
case OP_BREDOR: return Z3_OP_BREDOR;
|
||||
case OP_BREDAND: return Z3_OP_BREDAND;
|
||||
case OP_BCOMP: return Z3_OP_BCOMP;
|
||||
case OP_BSHL: return Z3_OP_BSHL;
|
||||
case OP_BLSHR: return Z3_OP_BLSHR;
|
||||
case OP_BASHR: return Z3_OP_BASHR;
|
||||
case OP_ROTATE_LEFT: return Z3_OP_ROTATE_LEFT;
|
||||
case OP_ROTATE_RIGHT: return Z3_OP_ROTATE_RIGHT;
|
||||
case OP_EXT_ROTATE_LEFT: return Z3_OP_EXT_ROTATE_LEFT;
|
||||
case OP_EXT_ROTATE_RIGHT: return Z3_OP_EXT_ROTATE_RIGHT;
|
||||
case OP_INT2BV: return Z3_OP_INT2BV;
|
||||
case OP_UBV2INT: return Z3_OP_BV2INT;
|
||||
case OP_SBV2INT: return Z3_OP_SBV2INT;
|
||||
case OP_CARRY: return Z3_OP_CARRY;
|
||||
case OP_XOR3: return Z3_OP_XOR3;
|
||||
case OP_BIT2BOOL: return Z3_OP_BIT2BOOL;
|
||||
case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL;
|
||||
case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL;
|
||||
case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL;
|
||||
case OP_BSDIV_I: return Z3_OP_BSDIV_I;
|
||||
case OP_BUDIV_I: return Z3_OP_BUDIV_I;
|
||||
case OP_BSREM_I: return Z3_OP_BSREM_I;
|
||||
case OP_BUREM_I: return Z3_OP_BUREM_I;
|
||||
case OP_BSMOD_I: return Z3_OP_BSMOD_I;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_dt_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR;
|
||||
case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER;
|
||||
case OP_DT_IS: return Z3_OP_DT_IS;
|
||||
case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR;
|
||||
case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
if (mk_c(c)->get_datalog_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case datalog::OP_RA_STORE: return Z3_OP_RA_STORE;
|
||||
case datalog::OP_RA_EMPTY: return Z3_OP_RA_EMPTY;
|
||||
case datalog::OP_RA_IS_EMPTY: return Z3_OP_RA_IS_EMPTY;
|
||||
case datalog::OP_RA_JOIN: return Z3_OP_RA_JOIN;
|
||||
case datalog::OP_RA_UNION: return Z3_OP_RA_UNION;
|
||||
case datalog::OP_RA_WIDEN: return Z3_OP_RA_WIDEN;
|
||||
case datalog::OP_RA_PROJECT: return Z3_OP_RA_PROJECT;
|
||||
case datalog::OP_RA_FILTER: return Z3_OP_RA_FILTER;
|
||||
case datalog::OP_RA_NEGATION_FILTER: return Z3_OP_RA_NEGATION_FILTER;
|
||||
case datalog::OP_RA_RENAME: return Z3_OP_RA_RENAME;
|
||||
case datalog::OP_RA_COMPLEMENT: return Z3_OP_RA_COMPLEMENT;
|
||||
case datalog::OP_RA_SELECT: return Z3_OP_RA_SELECT;
|
||||
case datalog::OP_RA_CLONE: return Z3_OP_RA_CLONE;
|
||||
case datalog::OP_DL_CONSTANT: return Z3_OP_FD_CONSTANT;
|
||||
case datalog::OP_DL_LT: return Z3_OP_FD_LT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_seq_fid() == _d->get_family_id()) {
|
||||
switch (_d->get_decl_kind()) {
|
||||
case OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT;
|
||||
case OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY;
|
||||
case OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS;
|
||||
case OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT;
|
||||
case OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE;
|
||||
case OP_SEQ_REPLACE_RE: return Z3_OP_SEQ_REPLACE_RE;
|
||||
case OP_SEQ_REPLACE_RE_ALL: return Z3_OP_SEQ_REPLACE_RE_ALL;
|
||||
case OP_SEQ_REPLACE_ALL: return Z3_OP_SEQ_REPLACE_ALL;
|
||||
case OP_SEQ_AT: return Z3_OP_SEQ_AT;
|
||||
case OP_SEQ_NTH: return Z3_OP_SEQ_NTH;
|
||||
case OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX;
|
||||
case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE;
|
||||
case OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE;
|
||||
case OP_SEQ_MAP: return Z3_OP_SEQ_MAP;
|
||||
case OP_SEQ_MAPI: return Z3_OP_SEQ_MAPI;
|
||||
case OP_SEQ_FOLDL: return Z3_OP_SEQ_FOLDL;
|
||||
case OP_SEQ_FOLDLI: return Z3_OP_SEQ_FOLDLI;
|
||||
|
||||
case _OP_STRING_STRREPL: return Z3_OP_SEQ_REPLACE;
|
||||
case _OP_STRING_CONCAT: return Z3_OP_SEQ_CONCAT;
|
||||
case _OP_STRING_LENGTH: return Z3_OP_SEQ_LENGTH;
|
||||
case _OP_STRING_STRCTN: return Z3_OP_SEQ_CONTAINS;
|
||||
case _OP_STRING_PREFIX: return Z3_OP_SEQ_PREFIX;
|
||||
case _OP_STRING_SUFFIX: return Z3_OP_SEQ_SUFFIX;
|
||||
case _OP_STRING_IN_REGEXP: return Z3_OP_SEQ_IN_RE;
|
||||
case _OP_STRING_TO_REGEXP: return Z3_OP_SEQ_TO_RE;
|
||||
case _OP_STRING_CHARAT: return Z3_OP_SEQ_AT;
|
||||
case _OP_STRING_SUBSTR: return Z3_OP_SEQ_EXTRACT;
|
||||
case _OP_STRING_STRIDOF: return Z3_OP_SEQ_INDEX;
|
||||
case _OP_REGEXP_EMPTY: return Z3_OP_RE_EMPTY_SET;
|
||||
case _OP_REGEXP_FULL_CHAR: return Z3_OP_RE_FULL_SET;
|
||||
|
||||
case OP_STRING_STOI: return Z3_OP_STR_TO_INT;
|
||||
case OP_STRING_ITOS: return Z3_OP_INT_TO_STR;
|
||||
case OP_STRING_TO_CODE: return Z3_OP_STR_TO_CODE;
|
||||
case OP_STRING_FROM_CODE: return Z3_OP_STR_FROM_CODE;
|
||||
|
||||
case OP_STRING_UBVTOS: return Z3_OP_UBV_TO_STR;
|
||||
case OP_STRING_SBVTOS: return Z3_OP_SBV_TO_STR;
|
||||
case OP_STRING_LT: return Z3_OP_STRING_LT;
|
||||
case OP_STRING_LE: return Z3_OP_STRING_LE;
|
||||
|
||||
case OP_RE_PLUS: return Z3_OP_RE_PLUS;
|
||||
case OP_RE_STAR: return Z3_OP_RE_STAR;
|
||||
case OP_RE_OPTION: return Z3_OP_RE_OPTION;
|
||||
case OP_RE_RANGE: return Z3_OP_RE_RANGE;
|
||||
case OP_RE_CONCAT: return Z3_OP_RE_CONCAT;
|
||||
case OP_RE_UNION: return Z3_OP_RE_UNION;
|
||||
case OP_RE_DIFF: return Z3_OP_RE_DIFF;
|
||||
case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT;
|
||||
case OP_RE_LOOP: return Z3_OP_RE_LOOP;
|
||||
case OP_RE_POWER: return Z3_OP_RE_POWER;
|
||||
case OP_RE_COMPLEMENT: return Z3_OP_RE_COMPLEMENT;
|
||||
case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET;
|
||||
|
||||
case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET;
|
||||
case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_CHAR_SET;
|
||||
case OP_RE_OF_PRED: return Z3_OP_RE_OF_PRED;
|
||||
case OP_RE_REVERSE: return Z3_OP_RE_REVERSE;
|
||||
case OP_RE_DERIVATIVE: return Z3_OP_RE_DERIVATIVE;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_char_fid() == _d->get_family_id()) {
|
||||
switch (_d->get_decl_kind()) {
|
||||
case OP_CHAR_CONST: return Z3_OP_CHAR_CONST;
|
||||
case OP_CHAR_LE: return Z3_OP_CHAR_LE;
|
||||
case OP_CHAR_TO_INT: return Z3_OP_CHAR_TO_INT;
|
||||
case OP_CHAR_TO_BV: return Z3_OP_CHAR_TO_BV;
|
||||
case OP_CHAR_FROM_BV: return Z3_OP_CHAR_FROM_BV;
|
||||
case OP_CHAR_IS_DIGIT: return Z3_OP_CHAR_IS_DIGIT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_fpa_fid() == _d->get_family_id()) {
|
||||
switch (_d->get_decl_kind()) {
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN;
|
||||
case OP_FPA_RM_NEAREST_TIES_TO_AWAY: return Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY;
|
||||
case OP_FPA_RM_TOWARD_POSITIVE: return Z3_OP_FPA_RM_TOWARD_POSITIVE;
|
||||
case OP_FPA_RM_TOWARD_NEGATIVE: return Z3_OP_FPA_RM_TOWARD_NEGATIVE;
|
||||
case OP_FPA_RM_TOWARD_ZERO: return Z3_OP_FPA_RM_TOWARD_ZERO;
|
||||
case OP_FPA_NUM: return Z3_OP_FPA_NUM;
|
||||
case OP_FPA_PLUS_INF: return Z3_OP_FPA_PLUS_INF;
|
||||
case OP_FPA_MINUS_INF: return Z3_OP_FPA_MINUS_INF;
|
||||
case OP_FPA_NAN: return Z3_OP_FPA_NAN;
|
||||
case OP_FPA_MINUS_ZERO: return Z3_OP_FPA_MINUS_ZERO;
|
||||
case OP_FPA_PLUS_ZERO: return Z3_OP_FPA_PLUS_ZERO;
|
||||
case OP_FPA_ADD: return Z3_OP_FPA_ADD;
|
||||
case OP_FPA_SUB: return Z3_OP_FPA_SUB;
|
||||
case OP_FPA_NEG: return Z3_OP_FPA_NEG;
|
||||
case OP_FPA_MUL: return Z3_OP_FPA_MUL;
|
||||
case OP_FPA_DIV: return Z3_OP_FPA_DIV;
|
||||
case OP_FPA_REM: return Z3_OP_FPA_REM;
|
||||
case OP_FPA_ABS: return Z3_OP_FPA_ABS;
|
||||
case OP_FPA_MIN: return Z3_OP_FPA_MIN;
|
||||
case OP_FPA_MAX: return Z3_OP_FPA_MAX;
|
||||
case OP_FPA_FMA: return Z3_OP_FPA_FMA;
|
||||
case OP_FPA_SQRT: return Z3_OP_FPA_SQRT;
|
||||
case OP_FPA_EQ: return Z3_OP_FPA_EQ;
|
||||
case OP_FPA_ROUND_TO_INTEGRAL: return Z3_OP_FPA_ROUND_TO_INTEGRAL;
|
||||
case OP_FPA_LT: return Z3_OP_FPA_LT;
|
||||
case OP_FPA_GT: return Z3_OP_FPA_GT;
|
||||
case OP_FPA_LE: return Z3_OP_FPA_LE;
|
||||
case OP_FPA_GE: return Z3_OP_FPA_GE;
|
||||
case OP_FPA_IS_NAN: return Z3_OP_FPA_IS_NAN;
|
||||
case OP_FPA_IS_INF: return Z3_OP_FPA_IS_INF;
|
||||
case OP_FPA_IS_ZERO: return Z3_OP_FPA_IS_ZERO;
|
||||
case OP_FPA_IS_NORMAL: return Z3_OP_FPA_IS_NORMAL;
|
||||
case OP_FPA_IS_SUBNORMAL: return Z3_OP_FPA_IS_SUBNORMAL;
|
||||
case OP_FPA_IS_NEGATIVE: return Z3_OP_FPA_IS_NEGATIVE;
|
||||
case OP_FPA_IS_POSITIVE: return Z3_OP_FPA_IS_POSITIVE;
|
||||
case OP_FPA_FP: return Z3_OP_FPA_FP;
|
||||
case OP_FPA_TO_FP: return Z3_OP_FPA_TO_FP;
|
||||
case OP_FPA_TO_FP_UNSIGNED: return Z3_OP_FPA_TO_FP_UNSIGNED;
|
||||
case OP_FPA_TO_UBV: return Z3_OP_FPA_TO_UBV;
|
||||
case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV;
|
||||
case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL;
|
||||
case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
|
||||
case OP_FPA_BVWRAP: return Z3_OP_FPA_BVWRAP;
|
||||
case OP_FPA_BV2RM: return Z3_OP_FPA_BV2RM;
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->m().get_label_family_id() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_LABEL: return Z3_OP_LABEL;
|
||||
case OP_LABEL_LIT: return Z3_OP_LABEL_LIT;
|
||||
default:
|
||||
return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->get_pb_fid() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_PB_LE: return Z3_OP_PB_LE;
|
||||
case OP_PB_GE: return Z3_OP_PB_GE;
|
||||
case OP_PB_EQ: return Z3_OP_PB_EQ;
|
||||
case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST;
|
||||
case OP_AT_LEAST_K: return Z3_OP_PB_AT_LEAST;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->fsutil().get_family_id() == _d->get_family_id()) {
|
||||
switch(_d->get_decl_kind()) {
|
||||
case OP_FINITE_SET_EMPTY: return Z3_OP_FINITE_SET_EMPTY;
|
||||
case OP_FINITE_SET_SINGLETON: return Z3_OP_FINITE_SET_SINGLETON;
|
||||
case OP_FINITE_SET_UNION: return Z3_OP_FINITE_SET_UNION;
|
||||
case OP_FINITE_SET_INTERSECT: return Z3_OP_FINITE_SET_INTERSECT;
|
||||
case OP_FINITE_SET_DIFFERENCE: return Z3_OP_FINITE_SET_DIFFERENCE;
|
||||
case OP_FINITE_SET_IN: return Z3_OP_FINITE_SET_IN;
|
||||
case OP_FINITE_SET_SIZE: return Z3_OP_FINITE_SET_SIZE;
|
||||
case OP_FINITE_SET_SUBSET: return Z3_OP_FINITE_SET_SUBSET;
|
||||
case OP_FINITE_SET_MAP: return Z3_OP_FINITE_SET_MAP;
|
||||
case OP_FINITE_SET_FILTER: return Z3_OP_FINITE_SET_FILTER;
|
||||
case OP_FINITE_SET_RANGE: return Z3_OP_FINITE_SET_RANGE;
|
||||
case OP_FINITE_SET_EXT: return Z3_OP_FINITE_SET_EXT;
|
||||
case OP_FINITE_SET_MAP_INVERSE: return Z3_OP_FINITE_SET_MAP_INVERSE;
|
||||
default: return Z3_OP_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mk_c(c)->recfun().get_family_id() == _d->get_family_id())
|
||||
if (mk_c(c)->get_basic_fid() == fid)
|
||||
return get_decl_kind_basic(k);
|
||||
if (mk_c(c)->get_arith_fid() == fid)
|
||||
return get_decl_kind_arith(k);
|
||||
if (mk_c(c)->get_bv_fid() == fid)
|
||||
return get_decl_kind_bv(k);
|
||||
if (mk_c(c)->get_array_fid() == fid)
|
||||
return get_decl_kind_array(k);
|
||||
if (mk_c(c)->get_dt_fid() == fid)
|
||||
return get_decl_kind_dt(k);
|
||||
if (mk_c(c)->get_seq_fid() == fid)
|
||||
return get_decl_kind_seq(k);
|
||||
if (mk_c(c)->get_fpa_fid() == fid)
|
||||
return get_decl_kind_fpa(k);
|
||||
if (mk_c(c)->get_datalog_fid() == fid)
|
||||
return get_decl_kind_datalog(k);
|
||||
if (mk_c(c)->get_pb_fid() == fid)
|
||||
return get_decl_kind_pb(k);
|
||||
if (mk_c(c)->get_special_relations_fid() == fid)
|
||||
return get_decl_kind_special_relations(k);
|
||||
if (mk_c(c)->get_char_fid() == fid)
|
||||
return get_decl_kind_char(k);
|
||||
if (mk_c(c)->m().get_label_family_id() == fid)
|
||||
return get_decl_kind_label(k);
|
||||
if (mk_c(c)->fsutil().get_family_id() == fid)
|
||||
return get_decl_kind_finite_set(k);
|
||||
if (mk_c(c)->recfun().get_family_id() == fid)
|
||||
return Z3_OP_RECURSIVE;
|
||||
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
|
|
@ -1505,11 +1522,7 @@ extern "C" {
|
|||
return 0;
|
||||
}
|
||||
var* va = to_var(_a);
|
||||
if (va) {
|
||||
return va->get_idx();
|
||||
}
|
||||
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
|
||||
return 0;
|
||||
return va->get_idx();
|
||||
Z3_CATCH_RETURN(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,8 +147,13 @@ endforeach()
|
|||
set(Z3_DOTNET_NUPKG_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_BUILD}")
|
||||
if(TARGET_ARCHITECTURE STREQUAL "i686")
|
||||
set(Z3_DOTNET_PLATFORM "x86")
|
||||
set(Z3_DOTNET_WIN_RID "win-x86")
|
||||
elseif(TARGET_ARCHITECTURE STREQUAL "arm64")
|
||||
set(Z3_DOTNET_PLATFORM "AnyCPU")
|
||||
set(Z3_DOTNET_WIN_RID "win-arm64")
|
||||
else()
|
||||
set(Z3_DOTNET_PLATFORM "AnyCPU")
|
||||
set(Z3_DOTNET_WIN_RID "win-x64")
|
||||
endif()
|
||||
|
||||
# TODO conditional for signing. we can then enable the ``Release_delaysign`` configuration
|
||||
|
|
|
|||
|
|
@ -562,6 +562,63 @@ namespace Microsoft.Z3
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a type variable sort for use as a parameter in polymorphic datatypes.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the type variable</param>
|
||||
public Sort MkTypeVariable(Symbol name)
|
||||
{
|
||||
Debug.Assert(name != null);
|
||||
CheckContextMatch(name);
|
||||
return new Sort(this, Native.Z3_mk_type_variable(nCtx, name.NativeObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a type variable sort for use as a parameter in polymorphic datatypes.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the type variable</param>
|
||||
public Sort MkTypeVariable(string name)
|
||||
{
|
||||
using var symbol = MkSymbol(name);
|
||||
return MkTypeVariable(symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a polymorphic datatype sort with explicit type parameters.
|
||||
/// Type parameters should be sorts created with <see cref="MkTypeVariable(string)"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the datatype sort</param>
|
||||
/// <param name="typeParams">array of type variable sorts</param>
|
||||
/// <param name="constructors">array of constructors</param>
|
||||
public DatatypeSort MkPolymorphicDatatypeSort(Symbol name, Sort[] typeParams, Constructor[] constructors)
|
||||
{
|
||||
Debug.Assert(name != null);
|
||||
Debug.Assert(typeParams != null);
|
||||
Debug.Assert(constructors != null);
|
||||
Debug.Assert(constructors.All(c => c != null));
|
||||
|
||||
CheckContextMatch(name);
|
||||
CheckContextMatch<Sort>(typeParams);
|
||||
CheckContextMatch<Constructor>(constructors);
|
||||
return new DatatypeSort(this,
|
||||
Native.Z3_mk_polymorphic_datatype(nCtx, name.NativeObject,
|
||||
(uint)typeParams.Length, AST.ArrayToNative(typeParams),
|
||||
(uint)constructors.Length, Z3Object.ArrayToNative(constructors)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a polymorphic datatype sort with explicit type parameters.
|
||||
/// Type parameters should be sorts created with <see cref="MkTypeVariable(string)"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">name of the datatype sort</param>
|
||||
/// <param name="typeParams">array of type variable sorts</param>
|
||||
/// <param name="constructors">array of constructors</param>
|
||||
public DatatypeSort MkPolymorphicDatatypeSort(string name, Sort[] typeParams, Constructor[] constructors)
|
||||
{
|
||||
using var symbol = MkSymbol(name);
|
||||
return MkPolymorphicDatatypeSort(symbol, typeParams, constructors);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a datatype field at expression t with value v.
|
||||
/// The function performs a record update at t. The field
|
||||
|
|
|
|||
|
|
@ -84,10 +84,10 @@ ${Z3_DOTNET_COMPILE_ITEMS}
|
|||
|
||||
<!-- TODO we may want to pack x64 and x86 native assemblies into a single nupkg -->
|
||||
|
||||
<!-- Native binaries x64 -->
|
||||
<!-- Native binaries x64/arm64 -->
|
||||
<ItemGroup Condition="'$(Platform)' != 'x86'">
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll')">
|
||||
<PackagePath>runtimes\win-x64\native</PackagePath>
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll')">
|
||||
<PackagePath>runtimes\${Z3_DOTNET_WIN_RID}\native</PackagePath>
|
||||
</Content>
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.so" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.so')">
|
||||
<PackagePath>runtimes\linux-x64\native</PackagePath>
|
||||
|
|
@ -99,7 +99,7 @@ ${Z3_DOTNET_COMPILE_ITEMS}
|
|||
|
||||
<!-- Native binaries for x86; currently only Windows is supported. -->
|
||||
<ItemGroup Condition="'$(Platform)' == 'x86'">
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$(_DN_CMAKE_CONFIG)/libz3.dll')">
|
||||
<Content Include="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll" Condition="Exists('${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libz3.dll')">
|
||||
<PackagePath>runtimes\win-x86\native</PackagePath>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
<!-- Probe the package root path -->
|
||||
<Z3_PACKAGE_PATH Condition="('$(Z3_PACKAGE_PATH)' == '')">$(MSBuildThisFileDirectory)..\</Z3_PACKAGE_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' != 'x86'">$(Z3_PACKAGE_PATH)runtimes\win-x64\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' == 'arm64'">$(Z3_PACKAGE_PATH)runtimes\win-arm64\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' != 'x86' and '$(Platform)' != 'arm64'">$(Z3_PACKAGE_PATH)runtimes\win-x64\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsWindows)' == 'true' and '$(Platform)' == 'x86'">$(Z3_PACKAGE_PATH)runtimes\win-x86\native\libz3.dll</Z3_NATIVE_LIB_PATH>
|
||||
<Z3_NATIVE_LIB_PATH Condition="'$(IsLinux)' == 'true'">$(Z3_PACKAGE_PATH)runtimes\linux-x64\native\libz3.so</Z3_NATIVE_LIB_PATH>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<ItemGroup Condition="!$(TargetFramework.Contains('netstandard')) and !$(TargetFramework.Contains('netcoreapp'))">
|
||||
<ItemGroup Condition="!$(TargetFramework.Contains('netstandard')) and !$(TargetFramework.Contains('netcoreapp')) and !$(TargetFramework.Contains('.'))">
|
||||
<None Include="$(Z3_NATIVE_LIB_PATH)">
|
||||
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
|
|
|||
43
src/api/go/char.go
Normal file
43
src/api/go/char.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Char operations
|
||||
|
||||
// MkCharSort creates the character sort (Unicode characters).
|
||||
func (c *Context) MkCharSort() *Sort {
|
||||
return newSort(c, C.Z3_mk_char_sort(c.ptr))
|
||||
}
|
||||
|
||||
// MkChar creates a character literal from a Unicode code point.
|
||||
func (c *Context) MkChar(ch uint) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char(c.ptr, C.uint(ch)))
|
||||
}
|
||||
|
||||
// MkCharLe creates a character less-than-or-equal predicate (ch1 ≤ ch2).
|
||||
func (c *Context) MkCharLe(ch1, ch2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_le(c.ptr, ch1.ptr, ch2.ptr))
|
||||
}
|
||||
|
||||
// MkCharToInt converts a character to its integer (Unicode code point) value.
|
||||
func (c *Context) MkCharToInt(ch *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_to_int(c.ptr, ch.ptr))
|
||||
}
|
||||
|
||||
// MkCharToBV converts a character to a bit-vector.
|
||||
func (c *Context) MkCharToBV(ch *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_to_bv(c.ptr, ch.ptr))
|
||||
}
|
||||
|
||||
// MkCharFromBV converts a bit-vector to a character.
|
||||
func (c *Context) MkCharFromBV(bv *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_from_bv(c.ptr, bv.ptr))
|
||||
}
|
||||
|
||||
// MkCharIsDigit creates a predicate that is true if the character is a decimal digit.
|
||||
func (c *Context) MkCharIsDigit(ch *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_char_is_digit(c.ptr, ch.ptr))
|
||||
}
|
||||
|
|
@ -127,6 +127,41 @@ func (c *Context) MkDatatypeSort(name string, constructors []*Constructor) *Sort
|
|||
return newSort(c, C.Z3_mk_datatype(c.ptr, sym.ptr, C.uint(numCons), &cons[0]))
|
||||
}
|
||||
|
||||
// MkPolymorphicDatatypeSort creates a polymorphic datatype sort with explicit type parameters.
|
||||
// typeParams should be sorts created with MkTypeVariable.
|
||||
// Self-recursive field sorts should be passed as nil; use the fieldSortRefs parameter in
|
||||
// MkConstructor to indicate the recursive reference by index.
|
||||
func (c *Context) MkPolymorphicDatatypeSort(name string, typeParams []*Sort, constructors []*Constructor) *Sort {
|
||||
sym := c.MkStringSymbol(name)
|
||||
|
||||
numParams := len(typeParams)
|
||||
numCons := len(constructors)
|
||||
|
||||
var paramPtr *C.Z3_sort
|
||||
if numParams > 0 {
|
||||
paramPtrs := make([]C.Z3_sort, numParams)
|
||||
for i, p := range typeParams {
|
||||
paramPtrs[i] = p.ptr
|
||||
}
|
||||
paramPtr = ¶mPtrs[0]
|
||||
}
|
||||
|
||||
var consPtr *C.Z3_constructor
|
||||
if numCons > 0 {
|
||||
consPtrs := make([]C.Z3_constructor, numCons)
|
||||
for i, cons := range constructors {
|
||||
consPtrs[i] = cons.ptr
|
||||
}
|
||||
consPtr = &consPtrs[0]
|
||||
}
|
||||
|
||||
return newSort(c, C.Z3_mk_polymorphic_datatype(
|
||||
c.ptr, sym.ptr,
|
||||
C.uint(numParams), paramPtr,
|
||||
C.uint(numCons), consPtr,
|
||||
))
|
||||
}
|
||||
|
||||
// MkDatatypeSorts creates multiple mutually recursive datatype sorts.
|
||||
func (c *Context) MkDatatypeSorts(names []string, constructorLists [][]*Constructor) []*Sort {
|
||||
numTypes := uint(len(names))
|
||||
|
|
|
|||
|
|
@ -218,6 +218,59 @@ func (f *Fixedpoint) FromFile(filename string) {
|
|||
C.Z3_fixedpoint_from_file(f.ctx.ptr, f.ptr, cstr)
|
||||
}
|
||||
|
||||
// QueryFromLvl poses a query against the asserted rules at the given level.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) QueryFromLvl(query *Expr, lvl uint) Status {
|
||||
result := C.Z3_fixedpoint_query_from_lvl(f.ctx.ptr, f.ptr, query.ptr, C.uint(lvl))
|
||||
switch result {
|
||||
case C.Z3_L_TRUE:
|
||||
return Satisfiable
|
||||
case C.Z3_L_FALSE:
|
||||
return Unsatisfiable
|
||||
default:
|
||||
return Unknown
|
||||
}
|
||||
}
|
||||
|
||||
// GetGroundSatAnswer retrieves a bottom-up sequence of ground facts.
|
||||
// The previous call to Query or QueryFromLvl must have returned Satisfiable.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetGroundSatAnswer() *Expr {
|
||||
ptr := C.Z3_fixedpoint_get_ground_sat_answer(f.ctx.ptr, f.ptr)
|
||||
if ptr == nil {
|
||||
return nil
|
||||
}
|
||||
return newExpr(f.ctx, ptr)
|
||||
}
|
||||
|
||||
// GetRulesAlongTrace returns the list of rules along the counterexample trace.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetRulesAlongTrace() *ASTVector {
|
||||
return newASTVector(f.ctx, C.Z3_fixedpoint_get_rules_along_trace(f.ctx.ptr, f.ptr))
|
||||
}
|
||||
|
||||
// GetRuleNamesAlongTrace returns the list of rule names along the counterexample trace.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetRuleNamesAlongTrace() *Symbol {
|
||||
return newSymbol(f.ctx, C.Z3_fixedpoint_get_rule_names_along_trace(f.ctx.ptr, f.ptr))
|
||||
}
|
||||
|
||||
// AddInvariant adds an assumed invariant for the predicate pred.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) AddInvariant(pred *FuncDecl, property *Expr) {
|
||||
C.Z3_fixedpoint_add_invariant(f.ctx.ptr, f.ptr, pred.ptr, property.ptr)
|
||||
}
|
||||
|
||||
// GetReachable retrieves the reachable states of a predicate.
|
||||
// This is a Spacer-specific function.
|
||||
func (f *Fixedpoint) GetReachable(pred *FuncDecl) *Expr {
|
||||
ptr := C.Z3_fixedpoint_get_reachable(f.ctx.ptr, f.ptr, pred.ptr)
|
||||
if ptr == nil {
|
||||
return nil
|
||||
}
|
||||
return newExpr(f.ctx, ptr)
|
||||
}
|
||||
|
||||
// Statistics represents statistics for Z3 solvers
|
||||
type Statistics struct {
|
||||
ctx *Context
|
||||
|
|
|
|||
38
src/api/go/relations.go
Normal file
38
src/api/go/relations.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Special relation constructors
|
||||
|
||||
// MkLinearOrder creates a linear (total) order relation over the given sort.
|
||||
// The id parameter distinguishes multiple linear orders over the same sort.
|
||||
func (c *Context) MkLinearOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_linear_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkPartialOrder creates a partial order relation over the given sort.
|
||||
// The id parameter distinguishes multiple partial orders over the same sort.
|
||||
func (c *Context) MkPartialOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_partial_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkPiecewiseLinearOrder creates a piecewise linear order relation over the given sort.
|
||||
// The id parameter distinguishes multiple piecewise linear orders over the same sort.
|
||||
func (c *Context) MkPiecewiseLinearOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_piecewise_linear_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkTreeOrder creates a tree order relation over the given sort.
|
||||
// The id parameter distinguishes multiple tree orders over the same sort.
|
||||
func (c *Context) MkTreeOrder(s *Sort, id uint) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_tree_order(c.ptr, s.ptr, C.uint(id)))
|
||||
}
|
||||
|
||||
// MkTransitiveClosure creates the transitive closure of a binary relation.
|
||||
// The resulting relation is recursive.
|
||||
func (c *Context) MkTransitiveClosure(f *FuncDecl) *FuncDecl {
|
||||
return newFuncDecl(c, C.Z3_mk_transitive_closure(c.ptr, f.ptr))
|
||||
}
|
||||
77
src/api/go/set.go
Normal file
77
src/api/go/set.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Regular (array-encoded) Set operations
|
||||
|
||||
// MkSetSort creates a set sort with the given element sort.
|
||||
func (c *Context) MkSetSort(elemSort *Sort) *Sort {
|
||||
return newSort(c, C.Z3_mk_set_sort(c.ptr, elemSort.ptr))
|
||||
}
|
||||
|
||||
// MkEmptySet creates an empty set of the given element sort.
|
||||
func (c *Context) MkEmptySet(elemSort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_empty_set(c.ptr, elemSort.ptr))
|
||||
}
|
||||
|
||||
// MkFullSet creates the full set (universe) of the given element sort.
|
||||
func (c *Context) MkFullSet(elemSort *Sort) *Expr {
|
||||
return newExpr(c, C.Z3_mk_full_set(c.ptr, elemSort.ptr))
|
||||
}
|
||||
|
||||
// MkSetAdd adds an element to a set.
|
||||
func (c *Context) MkSetAdd(set, elem *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_add(c.ptr, set.ptr, elem.ptr))
|
||||
}
|
||||
|
||||
// MkSetDel removes an element from a set.
|
||||
func (c *Context) MkSetDel(set, elem *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_del(c.ptr, set.ptr, elem.ptr))
|
||||
}
|
||||
|
||||
// MkSetUnion creates the union of two or more sets.
|
||||
func (c *Context) MkSetUnion(sets ...*Expr) *Expr {
|
||||
if len(sets) == 0 {
|
||||
return nil
|
||||
}
|
||||
cSets := make([]C.Z3_ast, len(sets))
|
||||
for i, s := range sets {
|
||||
cSets[i] = s.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_set_union(c.ptr, C.uint(len(sets)), &cSets[0]))
|
||||
}
|
||||
|
||||
// MkSetIntersect creates the intersection of two or more sets.
|
||||
func (c *Context) MkSetIntersect(sets ...*Expr) *Expr {
|
||||
if len(sets) == 0 {
|
||||
return nil
|
||||
}
|
||||
cSets := make([]C.Z3_ast, len(sets))
|
||||
for i, s := range sets {
|
||||
cSets[i] = s.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_set_intersect(c.ptr, C.uint(len(sets)), &cSets[0]))
|
||||
}
|
||||
|
||||
// MkSetDifference creates the set difference (set1 \ set2).
|
||||
func (c *Context) MkSetDifference(set1, set2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_difference(c.ptr, set1.ptr, set2.ptr))
|
||||
}
|
||||
|
||||
// MkSetComplement creates the complement of a set.
|
||||
func (c *Context) MkSetComplement(set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_complement(c.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkSetMember creates a membership predicate: elem ∈ set.
|
||||
func (c *Context) MkSetMember(elem, set *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_member(c.ptr, elem.ptr, set.ptr))
|
||||
}
|
||||
|
||||
// MkSetSubset creates a subset predicate: set1 ⊆ set2.
|
||||
func (c *Context) MkSetSubset(set1, set2 *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_mk_set_subset(c.ptr, set1.ptr, set2.ptr))
|
||||
}
|
||||
131
src/api/go/spacer.go
Normal file
131
src/api/go/spacer.go
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright (c) Microsoft Corporation 2025
|
||||
// Z3 Go API: Spacer quantifier elimination and model projection functions
|
||||
|
||||
package z3
|
||||
|
||||
/*
|
||||
#include "z3.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import "runtime"
|
||||
|
||||
// ASTMap represents a mapping from Z3 ASTs to Z3 ASTs.
|
||||
type ASTMap struct {
|
||||
ctx *Context
|
||||
ptr C.Z3_ast_map
|
||||
}
|
||||
|
||||
// newASTMap creates a new ASTMap and manages its reference count.
|
||||
func newASTMap(ctx *Context, ptr C.Z3_ast_map) *ASTMap {
|
||||
m := &ASTMap{ctx: ctx, ptr: ptr}
|
||||
C.Z3_ast_map_inc_ref(ctx.ptr, ptr)
|
||||
runtime.SetFinalizer(m, func(am *ASTMap) {
|
||||
C.Z3_ast_map_dec_ref(am.ctx.ptr, am.ptr)
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
||||
// MkASTMap creates a new empty AST map.
|
||||
func (c *Context) MkASTMap() *ASTMap {
|
||||
return newASTMap(c, C.Z3_mk_ast_map(c.ptr))
|
||||
}
|
||||
|
||||
// Contains returns true if the map contains the key k.
|
||||
func (m *ASTMap) Contains(k *Expr) bool {
|
||||
return bool(C.Z3_ast_map_contains(m.ctx.ptr, m.ptr, k.ptr))
|
||||
}
|
||||
|
||||
// Find returns the value associated with key k.
|
||||
func (m *ASTMap) Find(k *Expr) *Expr {
|
||||
return newExpr(m.ctx, C.Z3_ast_map_find(m.ctx.ptr, m.ptr, k.ptr))
|
||||
}
|
||||
|
||||
// Insert associates key k with value v in the map.
|
||||
func (m *ASTMap) Insert(k, v *Expr) {
|
||||
C.Z3_ast_map_insert(m.ctx.ptr, m.ptr, k.ptr, v.ptr)
|
||||
}
|
||||
|
||||
// Erase removes the entry with key k from the map.
|
||||
func (m *ASTMap) Erase(k *Expr) {
|
||||
C.Z3_ast_map_erase(m.ctx.ptr, m.ptr, k.ptr)
|
||||
}
|
||||
|
||||
// Reset removes all entries from the map.
|
||||
func (m *ASTMap) Reset() {
|
||||
C.Z3_ast_map_reset(m.ctx.ptr, m.ptr)
|
||||
}
|
||||
|
||||
// Size returns the number of entries in the map.
|
||||
func (m *ASTMap) Size() uint {
|
||||
return uint(C.Z3_ast_map_size(m.ctx.ptr, m.ptr))
|
||||
}
|
||||
|
||||
// Keys returns all keys in the map as an ASTVector.
|
||||
func (m *ASTMap) Keys() *ASTVector {
|
||||
return newASTVector(m.ctx, C.Z3_ast_map_keys(m.ctx.ptr, m.ptr))
|
||||
}
|
||||
|
||||
// String returns the string representation of the map.
|
||||
func (m *ASTMap) String() string {
|
||||
return C.GoString(C.Z3_ast_map_to_string(m.ctx.ptr, m.ptr))
|
||||
}
|
||||
|
||||
// ModelExtrapolate extrapolates a model of a formula.
|
||||
// Given a model m and formula fml, returns an expression that is implied by fml
|
||||
// and is consistent with the model. This is a Spacer-specific function.
|
||||
func (c *Context) ModelExtrapolate(m *Model, fml *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_model_extrapolate(c.ptr, m.ptr, fml.ptr))
|
||||
}
|
||||
|
||||
// QeLite performs best-effort quantifier elimination.
|
||||
// vars is a vector of variables to eliminate, body is the formula.
|
||||
func (c *Context) QeLite(vars *ASTVector, body *Expr) *Expr {
|
||||
return newExpr(c, C.Z3_qe_lite(c.ptr, vars.ptr, body.ptr))
|
||||
}
|
||||
|
||||
// QeModelProject projects variables given a model.
|
||||
// bound is a slice of application expressions representing the variables to project.
|
||||
func (c *Context) QeModelProject(m *Model, bound []*Expr, body *Expr) *Expr {
|
||||
n := len(bound)
|
||||
cBound := make([]C.Z3_app, n)
|
||||
for i, b := range bound {
|
||||
cBound[i] = C.Z3_to_app(c.ptr, b.ptr)
|
||||
}
|
||||
var boundPtr *C.Z3_app
|
||||
if n > 0 {
|
||||
boundPtr = &cBound[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_qe_model_project(c.ptr, m.ptr, C.uint(n), boundPtr, body.ptr))
|
||||
}
|
||||
|
||||
// QeModelProjectSkolem projects variables given a model, storing the skolem witnesses in map_.
|
||||
// bound is a slice of application expressions representing the variables to project.
|
||||
func (c *Context) QeModelProjectSkolem(m *Model, bound []*Expr, body *Expr, map_ *ASTMap) *Expr {
|
||||
n := len(bound)
|
||||
cBound := make([]C.Z3_app, n)
|
||||
for i, b := range bound {
|
||||
cBound[i] = C.Z3_to_app(c.ptr, b.ptr)
|
||||
}
|
||||
var boundPtr *C.Z3_app
|
||||
if n > 0 {
|
||||
boundPtr = &cBound[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_qe_model_project_skolem(c.ptr, m.ptr, C.uint(n), boundPtr, body.ptr, map_.ptr))
|
||||
}
|
||||
|
||||
// QeModelProjectWithWitness projects variables given a model and extracts witnesses.
|
||||
// The map_ is populated with bindings of projected variables to witness terms.
|
||||
// bound is a slice of application expressions representing the variables to project.
|
||||
func (c *Context) QeModelProjectWithWitness(m *Model, bound []*Expr, body *Expr, map_ *ASTMap) *Expr {
|
||||
n := len(bound)
|
||||
cBound := make([]C.Z3_app, n)
|
||||
for i, b := range bound {
|
||||
cBound[i] = C.Z3_to_app(c.ptr, b.ptr)
|
||||
}
|
||||
var boundPtr *C.Z3_app
|
||||
if n > 0 {
|
||||
boundPtr = &cBound[0]
|
||||
}
|
||||
return newExpr(c, C.Z3_qe_model_project_with_witness(c.ptr, m.ptr, C.uint(n), boundPtr, body.ptr, map_.ptr))
|
||||
}
|
||||
|
|
@ -228,6 +228,17 @@ func (g *Goal) String() string {
|
|||
return C.GoString(C.Z3_goal_to_string(g.ctx.ptr, g.ptr))
|
||||
}
|
||||
|
||||
// IsInconsistent returns true if the goal contains the formula false.
|
||||
func (g *Goal) IsInconsistent() bool {
|
||||
return bool(C.Z3_goal_inconsistent(g.ctx.ptr, g.ptr))
|
||||
}
|
||||
|
||||
// ToDimacsString converts the goal to a string in DIMACS format.
|
||||
// If includeNames is true, formula names are included as comments.
|
||||
func (g *Goal) ToDimacsString(includeNames bool) string {
|
||||
return C.GoString(C.Z3_goal_to_dimacs_string(g.ctx.ptr, g.ptr, C.bool(includeNames)))
|
||||
}
|
||||
|
||||
// ApplyResult represents the result of applying a tactic to a goal.
|
||||
type ApplyResult struct {
|
||||
ctx *Context
|
||||
|
|
|
|||
254
src/api/go/z3.go
254
src/api/go/z3.go
|
|
@ -240,6 +240,45 @@ func newExpr(ctx *Context, ptr C.Z3_ast) *Expr {
|
|||
return expr
|
||||
}
|
||||
|
||||
// intsToCs converts a []int slice to []C.int, returning the slice and
|
||||
// a pointer to its first element (nil if empty).
|
||||
func intsToCs(ints []int) ([]C.int, *C.int) {
|
||||
if len(ints) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cInts := make([]C.int, len(ints))
|
||||
for i, v := range ints {
|
||||
cInts[i] = C.int(v)
|
||||
}
|
||||
return cInts, &cInts[0]
|
||||
}
|
||||
|
||||
// exprsToASTs converts a []*Expr slice to []C.Z3_ast, returning the slice and
|
||||
// a pointer to its first element (nil if empty).
|
||||
func exprsToASTs(exprs []*Expr) ([]C.Z3_ast, *C.Z3_ast) {
|
||||
if len(exprs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
}
|
||||
return cExprs, &cExprs[0]
|
||||
}
|
||||
|
||||
// sortsToCSorts converts a []*Sort slice to []C.Z3_sort, returning the slice and
|
||||
// a pointer to its first element (nil if empty).
|
||||
func sortsToCSorts(sorts []*Sort) ([]C.Z3_sort, *C.Z3_sort) {
|
||||
if len(sorts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
cSorts := make([]C.Z3_sort, len(sorts))
|
||||
for i, s := range sorts {
|
||||
cSorts[i] = s.ptr
|
||||
}
|
||||
return cSorts, &cSorts[0]
|
||||
}
|
||||
|
||||
// String returns the string representation of the expression.
|
||||
func (e *Expr) String() string {
|
||||
return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr))
|
||||
|
|
@ -291,6 +330,21 @@ func newASTVector(ctx *Context, ptr C.Z3_ast_vector) *ASTVector {
|
|||
return v
|
||||
}
|
||||
|
||||
// Size returns the number of ASTs in the vector.
|
||||
func (v *ASTVector) Size() uint {
|
||||
return uint(C.Z3_ast_vector_size(v.ctx.ptr, v.ptr))
|
||||
}
|
||||
|
||||
// Get returns the i-th AST in the vector.
|
||||
func (v *ASTVector) Get(i uint) *Expr {
|
||||
return newExpr(v.ctx, C.Z3_ast_vector_get(v.ctx.ptr, v.ptr, C.uint(i)))
|
||||
}
|
||||
|
||||
// String returns the string representation of the AST vector.
|
||||
func (v *ASTVector) String() string {
|
||||
return C.GoString(C.Z3_ast_vector_to_string(v.ctx.ptr, v.ptr))
|
||||
}
|
||||
|
||||
// ParamDescrs represents parameter descriptions for Z3 objects.
|
||||
type ParamDescrs struct {
|
||||
ctx *Context
|
||||
|
|
@ -353,11 +407,8 @@ func (c *Context) MkAnd(exprs ...*Expr) *Expr {
|
|||
if len(exprs) == 1 {
|
||||
return exprs[0]
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
||||
_, cExprsPtr := exprsToASTs(exprs)
|
||||
return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||
}
|
||||
|
||||
// MkOr creates a disjunction.
|
||||
|
|
@ -368,11 +419,8 @@ func (c *Context) MkOr(exprs ...*Expr) *Expr {
|
|||
if len(exprs) == 1 {
|
||||
return exprs[0]
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
||||
_, cExprsPtr := exprsToASTs(exprs)
|
||||
return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||
}
|
||||
|
||||
// MkNot creates a negation.
|
||||
|
|
@ -407,11 +455,52 @@ func (c *Context) MkDistinct(exprs ...*Expr) *Expr {
|
|||
if len(exprs) <= 1 {
|
||||
return c.MkTrue()
|
||||
}
|
||||
cExprs := make([]C.Z3_ast, len(exprs))
|
||||
for i, e := range exprs {
|
||||
cExprs[i] = e.ptr
|
||||
_, cExprsPtr := exprsToASTs(exprs)
|
||||
return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||
}
|
||||
|
||||
// Pseudo-Boolean / cardinality constraints
|
||||
|
||||
// MkAtMost encodes p1 + p2 + ... + pn <= k.
|
||||
func (c *Context) MkAtMost(args []*Expr, k uint) *Expr {
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
return newExpr(c, C.Z3_mk_atmost(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
||||
}
|
||||
|
||||
// MkAtLeast encodes p1 + p2 + ... + pn >= k.
|
||||
func (c *Context) MkAtLeast(args []*Expr, k uint) *Expr {
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
return newExpr(c, C.Z3_mk_atleast(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
||||
}
|
||||
|
||||
// MkPBLe encodes k1*p1 + k2*p2 + ... + kn*pn <= k.
|
||||
func (c *Context) MkPBLe(args []*Expr, coeffs []int, k int) *Expr {
|
||||
if len(args) != len(coeffs) {
|
||||
panic("MkPBLe: args and coeffs must have the same length")
|
||||
}
|
||||
return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
_, cCoeffsPtr := intsToCs(coeffs)
|
||||
return newExpr(c, C.Z3_mk_pble(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||
}
|
||||
|
||||
// MkPBGe encodes k1*p1 + k2*p2 + ... + kn*pn >= k.
|
||||
func (c *Context) MkPBGe(args []*Expr, coeffs []int, k int) *Expr {
|
||||
if len(args) != len(coeffs) {
|
||||
panic("MkPBGe: args and coeffs must have the same length")
|
||||
}
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
_, cCoeffsPtr := intsToCs(coeffs)
|
||||
return newExpr(c, C.Z3_mk_pbge(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||
}
|
||||
|
||||
// MkPBEq encodes k1*p1 + k2*p2 + ... + kn*pn = k.
|
||||
func (c *Context) MkPBEq(args []*Expr, coeffs []int, k int) *Expr {
|
||||
if len(args) != len(coeffs) {
|
||||
panic("MkPBEq: args and coeffs must have the same length")
|
||||
}
|
||||
_, cArgsPtr := exprsToASTs(args)
|
||||
_, cCoeffsPtr := intsToCs(coeffs)
|
||||
return newExpr(c, C.Z3_mk_pbeq(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||
}
|
||||
|
||||
// FuncDecl represents a function declaration.
|
||||
|
|
@ -460,54 +549,26 @@ func (f *FuncDecl) GetRange() *Sort {
|
|||
|
||||
// MkFuncDecl creates a function declaration.
|
||||
func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
||||
cDomain := make([]C.Z3_sort, len(domain))
|
||||
for i, s := range domain {
|
||||
cDomain[i] = s.ptr
|
||||
}
|
||||
var domainPtr *C.Z3_sort
|
||||
if len(domain) > 0 {
|
||||
domainPtr = &cDomain[0]
|
||||
}
|
||||
_, domainPtr := sortsToCSorts(domain)
|
||||
return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
||||
}
|
||||
|
||||
// MkRecFuncDecl creates a recursive function declaration.
|
||||
// After creating, use AddRecDef to provide the function body.
|
||||
func (c *Context) MkRecFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
||||
cDomain := make([]C.Z3_sort, len(domain))
|
||||
for i, s := range domain {
|
||||
cDomain[i] = s.ptr
|
||||
}
|
||||
var domainPtr *C.Z3_sort
|
||||
if len(domain) > 0 {
|
||||
domainPtr = &cDomain[0]
|
||||
}
|
||||
_, domainPtr := sortsToCSorts(domain)
|
||||
return newFuncDecl(c, C.Z3_mk_rec_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
||||
}
|
||||
|
||||
// AddRecDef adds the definition (body) for a recursive function created with MkRecFuncDecl.
|
||||
func (c *Context) AddRecDef(f *FuncDecl, args []*Expr, body *Expr) {
|
||||
cArgs := make([]C.Z3_ast, len(args))
|
||||
for i, a := range args {
|
||||
cArgs[i] = a.ptr
|
||||
}
|
||||
var argsPtr *C.Z3_ast
|
||||
if len(args) > 0 {
|
||||
argsPtr = &cArgs[0]
|
||||
}
|
||||
_, argsPtr := exprsToASTs(args)
|
||||
C.Z3_add_rec_def(c.ptr, f.ptr, C.uint(len(args)), argsPtr, body.ptr)
|
||||
}
|
||||
|
||||
// MkApp creates a function application.
|
||||
func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr {
|
||||
cArgs := make([]C.Z3_ast, len(args))
|
||||
for i, a := range args {
|
||||
cArgs[i] = a.ptr
|
||||
}
|
||||
var argsPtr *C.Z3_ast
|
||||
if len(args) > 0 {
|
||||
argsPtr = &cArgs[0]
|
||||
}
|
||||
_, argsPtr := exprsToASTs(args)
|
||||
return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr))
|
||||
}
|
||||
|
||||
|
|
@ -546,6 +607,66 @@ func (e *Expr) Simplify() *Expr {
|
|||
return newExpr(e.ctx, C.Z3_simplify(e.ctx.ptr, e.ptr))
|
||||
}
|
||||
|
||||
// GetDecl returns the function declaration of an application expression.
|
||||
func (e *Expr) GetDecl() *FuncDecl {
|
||||
return newFuncDecl(e.ctx, C.Z3_get_app_decl(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr)))
|
||||
}
|
||||
|
||||
// NumArgs returns the number of arguments of an application expression.
|
||||
func (e *Expr) NumArgs() uint {
|
||||
return uint(C.Z3_get_app_num_args(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr)))
|
||||
}
|
||||
|
||||
// Arg returns the i-th argument of an application expression.
|
||||
func (e *Expr) Arg(i uint) *Expr {
|
||||
return newExpr(e.ctx, C.Z3_get_app_arg(e.ctx.ptr, C.Z3_to_app(e.ctx.ptr, e.ptr), C.uint(i)))
|
||||
}
|
||||
|
||||
// Substitute replaces every occurrence of from[i] in the expression with to[i].
|
||||
// The from and to slices must have the same length.
|
||||
func (e *Expr) Substitute(from, to []*Expr) *Expr {
|
||||
n := len(from)
|
||||
cFrom := make([]C.Z3_ast, n)
|
||||
cTo := make([]C.Z3_ast, n)
|
||||
for i := range from {
|
||||
cFrom[i] = from[i].ptr
|
||||
cTo[i] = to[i].ptr
|
||||
}
|
||||
var fromPtr, toPtr *C.Z3_ast
|
||||
if n > 0 {
|
||||
fromPtr = &cFrom[0]
|
||||
toPtr = &cTo[0]
|
||||
}
|
||||
return newExpr(e.ctx, C.Z3_substitute(e.ctx.ptr, e.ptr, C.uint(n), fromPtr, toPtr))
|
||||
}
|
||||
|
||||
// SubstituteVars replaces free variables in the expression with the expressions in to.
|
||||
// Variable with de-Bruijn index i is replaced with to[i].
|
||||
func (e *Expr) SubstituteVars(to []*Expr) *Expr {
|
||||
_, toPtr := exprsToASTs(to)
|
||||
return newExpr(e.ctx, C.Z3_substitute_vars(e.ctx.ptr, e.ptr, C.uint(len(to)), toPtr))
|
||||
}
|
||||
|
||||
// SubstituteFuns replaces every occurrence of from[i] applied to arguments
|
||||
// with to[i] in the expression.
|
||||
// The from and to slices must have the same length.
|
||||
func (e *Expr) SubstituteFuns(from []*FuncDecl, to []*Expr) *Expr {
|
||||
n := len(from)
|
||||
cFrom := make([]C.Z3_func_decl, n)
|
||||
cTo := make([]C.Z3_ast, n)
|
||||
for i := range from {
|
||||
cFrom[i] = from[i].ptr
|
||||
cTo[i] = to[i].ptr
|
||||
}
|
||||
var fromPtr *C.Z3_func_decl
|
||||
var toPtr *C.Z3_ast
|
||||
if n > 0 {
|
||||
fromPtr = &cFrom[0]
|
||||
toPtr = &cTo[0]
|
||||
}
|
||||
return newExpr(e.ctx, C.Z3_substitute_funs(e.ctx.ptr, e.ptr, C.uint(n), fromPtr, toPtr))
|
||||
}
|
||||
|
||||
// MkTypeVariable creates a type variable sort for use in polymorphic functions and datatypes
|
||||
func (c *Context) MkTypeVariable(name *Symbol) *Sort {
|
||||
return newSort(c, C.Z3_mk_type_variable(c.ptr, name.ptr))
|
||||
|
|
@ -639,12 +760,7 @@ func (q *Quantifier) String() string {
|
|||
|
||||
// MkQuantifier creates a quantifier with patterns
|
||||
func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier {
|
||||
var forallInt C.bool
|
||||
if isForall {
|
||||
forallInt = true
|
||||
} else {
|
||||
forallInt = false
|
||||
}
|
||||
forallInt := C.bool(isForall)
|
||||
|
||||
numBound := len(sorts)
|
||||
if numBound != len(names) {
|
||||
|
|
@ -687,12 +803,7 @@ func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names [
|
|||
|
||||
// MkQuantifierConst creates a quantifier using constant bound variables
|
||||
func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier {
|
||||
var forallInt C.bool
|
||||
if isForall {
|
||||
forallInt = true
|
||||
} else {
|
||||
forallInt = false
|
||||
}
|
||||
forallInt := C.bool(isForall)
|
||||
|
||||
numBound := len(bound)
|
||||
var cBound []C.Z3_app
|
||||
|
|
@ -815,6 +926,33 @@ func (c *Context) MkLambdaConst(bound []*Expr, body *Expr) *Lambda {
|
|||
return newLambda(c, ptr)
|
||||
}
|
||||
|
||||
// SetGlobalParam sets a global Z3 parameter.
|
||||
func SetGlobalParam(id, value string) {
|
||||
cID := C.CString(id)
|
||||
cValue := C.CString(value)
|
||||
defer C.free(unsafe.Pointer(cID))
|
||||
defer C.free(unsafe.Pointer(cValue))
|
||||
C.Z3_global_param_set(cID, cValue)
|
||||
}
|
||||
|
||||
// GetGlobalParam retrieves the value of a global Z3 parameter.
|
||||
// Returns the value and true if the parameter exists, or empty string and false otherwise.
|
||||
func GetGlobalParam(id string) (string, bool) {
|
||||
cID := C.CString(id)
|
||||
defer C.free(unsafe.Pointer(cID))
|
||||
var cValue C.Z3_string
|
||||
ok := C.Z3_global_param_get(cID, &cValue)
|
||||
if ok == C.bool(false) {
|
||||
return "", false
|
||||
}
|
||||
return C.GoString(cValue), true
|
||||
}
|
||||
|
||||
// ResetAllGlobalParams resets all global Z3 parameters to their default values.
|
||||
func ResetAllGlobalParams() {
|
||||
C.Z3_global_param_reset_all()
|
||||
}
|
||||
|
||||
// astVectorToExprs converts a Z3_ast_vector to a slice of Expr.
|
||||
// This function properly manages the reference count of the vector by
|
||||
// incrementing it on entry and decrementing it on exit.
|
||||
|
|
|
|||
|
|
@ -4616,6 +4616,38 @@ public class Context implements AutoCloseable {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a piecewise linear order.
|
||||
* @param index The index of the order.
|
||||
* @param sort The sort of the order.
|
||||
*/
|
||||
public final <R extends Sort> FuncDecl<BoolSort> mkPiecewiseLinearOrder(R sort, int index) {
|
||||
return (FuncDecl<BoolSort>) FuncDecl.create(
|
||||
this,
|
||||
Native.mkPiecewiseLinearOrder(
|
||||
nCtx(),
|
||||
sort.getNativeObject(),
|
||||
index
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tree order.
|
||||
* @param index The index of the order.
|
||||
* @param sort The sort of the order.
|
||||
*/
|
||||
public final <R extends Sort> FuncDecl<BoolSort> mkTreeOrder(R sort, int index) {
|
||||
return (FuncDecl<BoolSort>) FuncDecl.create(
|
||||
this,
|
||||
Native.mkTreeOrder(
|
||||
nCtx(),
|
||||
sort.getNativeObject(),
|
||||
index
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the nonzero subresultants of p and q with respect to the "variable" x.
|
||||
* Note that any subterm that cannot be viewed as a polynomial is assumed to be a variable.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,17 @@ const {
|
|||
|
||||
This package has different initialization for browser and node. Your bundler and node should choose good version automatically, but you can import the one you need manually - `const { init } = require('z3-solver/node');` or `const { init } = require('z3-solver/browser');`.
|
||||
|
||||
The `init` function also accepts an optional Emscripten module overrides object. This is useful in runtimes such as Deno where you may want to provide a wasm load path explicitly instead of relying on filesystem reads. In Deno 2.1+, `import.meta.resolve(...)` returns a string synchronously, so it can be used directly in `locateFile`. For example:
|
||||
|
||||
```typescript
|
||||
import { init } from 'npm:z3-solver';
|
||||
|
||||
const api = await init({
|
||||
locateFile: (file, _prefix): string =>
|
||||
import.meta.resolve(`npm:z3-solver/build/${file}`), // _prefix is unused here
|
||||
});
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
The package requires threads, which means you'll need to be running in an environment which supports `SharedArrayBuffer`. In browsers, in addition to ensuring the browser has implemented `SharedArrayBuffer`, you'll need to serve your page with [special headers](https://web.dev/coop-coep/). There's a [neat trick](https://github.com/gzuidhof/coi-serviceworker) for doing that client-side on e.g. Github Pages, though you shouldn't use that trick in more complex applications.
|
||||
|
|
|
|||
7
src/api/js/package-lock.json
generated
7
src/api/js/package-lock.json
generated
|
|
@ -5842,10 +5842,11 @@
|
|||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -444,8 +444,8 @@ ${Object.entries(primitiveTypes)
|
|||
.map(e => `type ${e[0]} = ${e[1]};`)
|
||||
.join('\n')}
|
||||
|
||||
export async function init(initModule: any) {
|
||||
let Mod = await initModule();
|
||||
export async function init(initModule: any, moduleOverrides: Record<string, unknown> = {}) {
|
||||
let Mod = await initModule(moduleOverrides);
|
||||
|
||||
// this works for both signed and unsigned, because JS will wrap for you when constructing the Uint32Array
|
||||
function intArrayToByteArr(ints: number[]) {
|
||||
|
|
@ -461,13 +461,13 @@ export async function init(initModule: any) {
|
|||
}
|
||||
|
||||
let outAddress = Mod._malloc(${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS});
|
||||
let outUintArray = (new Uint32Array(Mod.HEAPU32.buffer, outAddress, 4));
|
||||
let outUintArray = (new Uint32Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 4}));
|
||||
let getOutUint = (i: ${getValidOutArrayIndexes(4)}) => outUintArray[i];
|
||||
let outIntArray = (new Int32Array(Mod.HEAPU32.buffer, outAddress, 4));
|
||||
let outIntArray = (new Int32Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 4}));
|
||||
let getOutInt = (i: ${getValidOutArrayIndexes(4)}) => outIntArray[i];
|
||||
let outUint64Array = (new BigUint64Array(Mod.HEAPU32.buffer, outAddress, 2));
|
||||
let outUint64Array = (new BigUint64Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 8}));
|
||||
let getOutUint64 = (i: ${getValidOutArrayIndexes(8)}) => outUint64Array[i];
|
||||
let outInt64Array = (new BigInt64Array(Mod.HEAPU32.buffer, outAddress, 2));
|
||||
let outInt64Array = (new BigInt64Array(Mod.HEAPU32.buffer, outAddress, ${BYTES_TO_ALLOCATE_FOR_OUT_PARAMS / 8}));
|
||||
let getOutInt64 = (i: ${getValidOutArrayIndexes(8)}) => outInt64Array[i];
|
||||
|
||||
return {
|
||||
|
|
|
|||
43
src/api/js/src/browser.test.ts
Normal file
43
src/api/js/src/browser.test.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
const mockInitWrapper = jest.fn();
|
||||
const mockCreateApi = jest.fn();
|
||||
|
||||
jest.mock('./low-level', () => ({
|
||||
init: mockInitWrapper,
|
||||
Z3Core: undefined,
|
||||
Z3LowLevel: undefined,
|
||||
}));
|
||||
jest.mock('./high-level', () => ({
|
||||
createApi: mockCreateApi,
|
||||
}));
|
||||
|
||||
import { init } from './browser';
|
||||
|
||||
describe('browser init', () => {
|
||||
beforeEach(() => {
|
||||
delete (global as any).initZ3;
|
||||
mockInitWrapper.mockReset();
|
||||
mockCreateApi.mockReset();
|
||||
});
|
||||
|
||||
it('passes module overrides to the browser initializer', async () => {
|
||||
const initZ3 = jest.fn();
|
||||
const locateFile = jest.fn((file: string) => `https://example.test/${file}`);
|
||||
const lowLevel = { Z3: { low: true }, em: { module: true } };
|
||||
const highLevel = { Context: jest.fn() };
|
||||
(global as any).initZ3 = initZ3;
|
||||
mockInitWrapper.mockResolvedValue(lowLevel);
|
||||
mockCreateApi.mockReturnValue(highLevel);
|
||||
|
||||
const api = await init({ locateFile });
|
||||
|
||||
expect(mockInitWrapper).toHaveBeenCalledWith(initZ3, { locateFile });
|
||||
expect(mockCreateApi).toHaveBeenCalledWith(lowLevel.Z3, lowLevel.em);
|
||||
expect(api).toEqual({ ...lowLevel, ...highLevel });
|
||||
});
|
||||
|
||||
it('throws when initZ3 is unavailable', async () => {
|
||||
await expect(init()).rejects.toThrow(
|
||||
'initZ3 was not imported correctly. Please consult documentation on how to load Z3 in browser',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
import { createApi, Z3HighLevel } from './high-level';
|
||||
import { init as initWrapper, Z3LowLevel } from './low-level';
|
||||
import { init as initWrapper, Z3LowLevel, Z3ModuleOverrides } from './low-level';
|
||||
export * from './high-level/types';
|
||||
export { Z3Core, Z3LowLevel } from './low-level';
|
||||
export * from './low-level/types.__GENERATED__';
|
||||
|
||||
export async function init(): Promise<Z3LowLevel & Z3HighLevel> {
|
||||
export async function init(moduleOverrides: Z3ModuleOverrides = {}): Promise<Z3LowLevel & Z3HighLevel> {
|
||||
const initZ3 = (global as any).initZ3;
|
||||
if (initZ3 === undefined) {
|
||||
throw new Error('initZ3 was not imported correctly. Please consult documentation on how to load Z3 in browser');
|
||||
}
|
||||
|
||||
const lowLevel = await initWrapper(initZ3);
|
||||
const lowLevel = await initWrapper(initZ3, moduleOverrides);
|
||||
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||
return { ...lowLevel, ...highLevel };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1172,9 +1172,16 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
|||
createDatatypes(...datatypes: DatatypeImpl[]): DatatypeSortImpl[] {
|
||||
return createDatatypes(...datatypes);
|
||||
},
|
||||
createPolymorphicDatatype(typeParams: Sort<Name>[], datatype: DatatypeImpl): DatatypeSortImpl {
|
||||
return createPolymorphicDatatype(typeParams, datatype);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
function TypeVariable(name: string): Sort<Name> {
|
||||
return new SortImpl(check(Z3.mk_type_variable(contextPtr, Z3.mk_string_symbol(contextPtr, name))));
|
||||
}
|
||||
|
||||
////////////////
|
||||
// Operations //
|
||||
////////////////
|
||||
|
|
@ -1950,10 +1957,46 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
|||
return new FuncDeclImpl(check(Z3.mk_partial_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_linear_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkPiecewiseLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_piecewise_linear_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkTreeOrder(sort: Sort<Name>, index: number): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_tree_order(contextPtr, sort.ptr, index)));
|
||||
}
|
||||
|
||||
function mkTransitiveClosure(f: FuncDecl<Name>): FuncDecl<Name> {
|
||||
return new FuncDeclImpl(check(Z3.mk_transitive_closure(contextPtr, f.ptr)));
|
||||
}
|
||||
|
||||
function mkChar(ch: number): Expr<Name> {
|
||||
return new ExprImpl(check(Z3.mk_char(contextPtr, ch)));
|
||||
}
|
||||
|
||||
function mkCharLe(ch1: Expr<Name>, ch2: Expr<Name>): Bool<Name> {
|
||||
return new BoolImpl(check(Z3.mk_char_le(contextPtr, ch1.ast, ch2.ast)));
|
||||
}
|
||||
|
||||
function mkCharToInt(ch: Expr<Name>): Arith<Name> {
|
||||
return new ArithImpl(check(Z3.mk_char_to_int(contextPtr, ch.ast)));
|
||||
}
|
||||
|
||||
function mkCharToBV(ch: Expr<Name>): Expr<Name> {
|
||||
return new ExprImpl(check(Z3.mk_char_to_bv(contextPtr, ch.ast)));
|
||||
}
|
||||
|
||||
function mkCharFromBV(bv: Expr<Name>): Expr<Name> {
|
||||
return new ExprImpl(check(Z3.mk_char_from_bv(contextPtr, bv.ast)));
|
||||
}
|
||||
|
||||
function mkCharIsDigit(ch: Expr<Name>): Bool<Name> {
|
||||
return new BoolImpl(check(Z3.mk_char_is_digit(contextPtr, ch.ast)));
|
||||
}
|
||||
|
||||
async function polynomialSubresultants(
|
||||
p: Arith<Name>,
|
||||
q: Arith<Name>,
|
||||
|
|
@ -4689,6 +4732,10 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
|||
const datatypes = createDatatypes(this);
|
||||
return datatypes[0];
|
||||
}
|
||||
|
||||
createPolymorphic(typeParams: Sort<Name>[]): DatatypeSort<Name> {
|
||||
return createPolymorphicDatatype(typeParams, this);
|
||||
}
|
||||
}
|
||||
|
||||
class DatatypeSortImpl extends SortImpl implements DatatypeSort<Name> {
|
||||
|
|
@ -4845,6 +4892,84 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
|||
}
|
||||
}
|
||||
|
||||
function createPolymorphicDatatype(typeParams: Sort<Name>[], datatype: DatatypeImpl): DatatypeSortImpl {
|
||||
if (!(datatype instanceof DatatypeImpl)) {
|
||||
throw new Error('Datatype instance expected');
|
||||
}
|
||||
|
||||
const constructors: Z3_constructor[] = [];
|
||||
|
||||
try {
|
||||
for (const [constructorName, fields] of datatype.constructors) {
|
||||
const fieldNames: string[] = [];
|
||||
const fieldSorts: Z3_sort[] = [];
|
||||
const fieldRefs: number[] = [];
|
||||
|
||||
for (const [fieldName, fieldSort] of fields) {
|
||||
fieldNames.push(fieldName);
|
||||
|
||||
if (fieldSort instanceof DatatypeImpl) {
|
||||
// Self-recursive reference
|
||||
if (fieldSort !== datatype) {
|
||||
throw new Error(
|
||||
`Referenced datatype "${fieldSort.name}" is not the polymorphic datatype being created; mutual recursion is not supported in createPolymorphicDatatype`,
|
||||
);
|
||||
}
|
||||
fieldSorts.push(null as any);
|
||||
fieldRefs.push(0);
|
||||
} else {
|
||||
fieldSorts.push((fieldSort as Sort<Name>).ptr);
|
||||
fieldRefs.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
const constructor = Z3.mk_constructor(
|
||||
contextPtr,
|
||||
Z3.mk_string_symbol(contextPtr, constructorName),
|
||||
Z3.mk_string_symbol(contextPtr, `is_${constructorName}`),
|
||||
fieldNames.map(name => Z3.mk_string_symbol(contextPtr, name)),
|
||||
fieldSorts,
|
||||
fieldRefs,
|
||||
);
|
||||
constructors.push(constructor);
|
||||
}
|
||||
|
||||
const nameSymbol = Z3.mk_string_symbol(contextPtr, datatype.name);
|
||||
const paramPtrs = typeParams.map(p => p.ptr);
|
||||
const resultSort = Z3.mk_polymorphic_datatype(contextPtr, nameSymbol, paramPtrs, constructors);
|
||||
|
||||
const sortImpl = new DatatypeSortImpl(resultSort);
|
||||
|
||||
// Attach constructor, recognizer, and accessor functions dynamically
|
||||
const numConstructors = sortImpl.numConstructors();
|
||||
for (let j = 0; j < numConstructors; j++) {
|
||||
const constructor = sortImpl.constructorDecl(j);
|
||||
const recognizer = sortImpl.recognizer(j);
|
||||
const constructorName = constructor.name().toString();
|
||||
|
||||
if (constructor.arity() === 0) {
|
||||
(sortImpl as any)[constructorName] = constructor.call();
|
||||
} else {
|
||||
(sortImpl as any)[constructorName] = constructor;
|
||||
}
|
||||
|
||||
(sortImpl as any)[`is_${constructorName}`] = recognizer;
|
||||
|
||||
for (let k = 0; k < constructor.arity(); k++) {
|
||||
const accessor = sortImpl.accessor(j, k);
|
||||
const accessorName = accessor.name().toString();
|
||||
(sortImpl as any)[accessorName] = accessor;
|
||||
}
|
||||
}
|
||||
|
||||
return sortImpl;
|
||||
} finally {
|
||||
for (const constructor of constructors) {
|
||||
Z3.del_constructor(contextPtr, constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QuantifierImpl<
|
||||
QVarSorts extends NonEmptySortArray<Name>,
|
||||
QSort extends BoolSort<Name> | SMTArraySort<Name, QVarSorts>,
|
||||
|
|
@ -5292,6 +5417,7 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
|||
Set,
|
||||
FiniteSet,
|
||||
Datatype,
|
||||
TypeVariable,
|
||||
|
||||
////////////////
|
||||
// Operations //
|
||||
|
|
@ -5400,7 +5526,16 @@ export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
|||
Full,
|
||||
|
||||
mkPartialOrder,
|
||||
mkLinearOrder,
|
||||
mkPiecewiseLinearOrder,
|
||||
mkTreeOrder,
|
||||
mkTransitiveClosure,
|
||||
mkChar,
|
||||
mkCharLe,
|
||||
mkCharToInt,
|
||||
mkCharToBV,
|
||||
mkCharFromBV,
|
||||
mkCharIsDigit,
|
||||
polynomialSubresultants,
|
||||
};
|
||||
cleanup.register(ctx, () => Z3.del_context(contextPtr));
|
||||
|
|
|
|||
|
|
@ -479,6 +479,12 @@ export interface Context<Name extends string = 'main'> {
|
|||
/** @category Expressions */
|
||||
readonly Datatype: DatatypeCreation<Name>;
|
||||
|
||||
/**
|
||||
* Create a type variable sort for use as a parameter in polymorphic datatypes.
|
||||
* @category Sorts
|
||||
*/
|
||||
TypeVariable(name: string): Sort<Name>;
|
||||
|
||||
////////////////
|
||||
// Operations //
|
||||
////////////////
|
||||
|
|
@ -927,6 +933,30 @@ export interface Context<Name extends string = 'main'> {
|
|||
*/
|
||||
mkPartialOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a linear (total) order relation over a sort.
|
||||
* @param sort The sort of the relation
|
||||
* @param index The index of the relation
|
||||
* @category Operations
|
||||
*/
|
||||
mkLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a piecewise linear order relation over a sort.
|
||||
* @param sort The sort of the relation
|
||||
* @param index The index of the relation
|
||||
* @category Operations
|
||||
*/
|
||||
mkPiecewiseLinearOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a tree order relation over a sort.
|
||||
* @param sort The sort of the relation
|
||||
* @param index The index of the relation
|
||||
* @category Operations
|
||||
*/
|
||||
mkTreeOrder(sort: Sort<Name>, index: number): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create the transitive closure of a binary relation.
|
||||
* The resulting relation is recursive.
|
||||
|
|
@ -935,6 +965,49 @@ export interface Context<Name extends string = 'main'> {
|
|||
*/
|
||||
mkTransitiveClosure(f: FuncDecl<Name>): FuncDecl<Name>;
|
||||
|
||||
/**
|
||||
* Create a character literal from a Unicode code point.
|
||||
* @param ch The Unicode code point
|
||||
* @category Characters
|
||||
*/
|
||||
mkChar(ch: number): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Create a character less-than-or-equal predicate (ch1 ≤ ch2).
|
||||
* @param ch1 First character
|
||||
* @param ch2 Second character
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharLe(ch1: Expr<Name>, ch2: Expr<Name>): Bool<Name>;
|
||||
|
||||
/**
|
||||
* Convert a character to its integer (Unicode code point) value.
|
||||
* @param ch The character expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharToInt(ch: Expr<Name>): Arith<Name>;
|
||||
|
||||
/**
|
||||
* Convert a character to a bit-vector.
|
||||
* @param ch The character expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharToBV(ch: Expr<Name>): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Convert a bit-vector to a character.
|
||||
* @param bv The bit-vector expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharFromBV(bv: Expr<Name>): Expr<Name>;
|
||||
|
||||
/**
|
||||
* Create a predicate that is true if the character is a decimal digit.
|
||||
* @param ch The character expression
|
||||
* @category Characters
|
||||
*/
|
||||
mkCharIsDigit(ch: Expr<Name>): Bool<Name>;
|
||||
|
||||
/**
|
||||
* Return the nonzero subresultants of p and q with respect to the "variable" x.
|
||||
* Note that any subterm that cannot be viewed as a polynomial is assumed to be a variable.
|
||||
|
|
@ -3136,6 +3209,15 @@ export interface Datatype<Name extends string = 'main'> {
|
|||
* For mutually recursive datatypes, use Context.createDatatypes instead.
|
||||
*/
|
||||
create(): DatatypeSort<Name>;
|
||||
|
||||
/**
|
||||
* Create a polymorphic datatype sort with explicit type parameters.
|
||||
* Type parameters should be sorts created with Context.TypeVariable.
|
||||
* Self-recursive fields may reference this Datatype object directly.
|
||||
*
|
||||
* @param typeParams Array of type variable sorts
|
||||
*/
|
||||
createPolymorphic(typeParams: AnySort<Name>[]): DatatypeSort<Name>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3154,6 +3236,17 @@ export interface DatatypeCreation<Name extends string> {
|
|||
* @returns Array of created DatatypeSort instances
|
||||
*/
|
||||
createDatatypes(...datatypes: Datatype<Name>[]): DatatypeSort<Name>[];
|
||||
|
||||
/**
|
||||
* Create a single polymorphic datatype sort with explicit type parameters.
|
||||
* Type parameters should be sorts created with Context.TypeVariable.
|
||||
* Self-recursive fields in constructors may reference the Datatype object directly.
|
||||
*
|
||||
* @param typeParams Array of type variable sorts
|
||||
* @param datatype Datatype declaration with constructors
|
||||
* @returns Created DatatypeSort instance
|
||||
*/
|
||||
createPolymorphicDatatype(typeParams: AnySort<Name>[], datatype: Datatype<Name>): DatatypeSort<Name>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
export * from './types.__GENERATED__';
|
||||
export * from './wrapper.__GENERATED__';
|
||||
export type Z3ModuleOverrides = {
|
||||
locateFile?: (path: string, prefix: string) => string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
export type Z3Core = Awaited<ReturnType<(typeof import('./wrapper.__GENERATED__'))['init']>>['Z3'];
|
||||
export type Z3LowLevel = Awaited<ReturnType<(typeof import('./wrapper.__GENERATED__'))['init']>>;
|
||||
|
|
|
|||
37
src/api/js/src/node.test.ts
Normal file
37
src/api/js/src/node.test.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
const mockInitModule = jest.fn();
|
||||
const mockInitWrapper = jest.fn();
|
||||
const mockCreateApi = jest.fn();
|
||||
|
||||
jest.mock('./z3-built', () => mockInitModule, { virtual: true });
|
||||
jest.mock('./low-level', () => ({
|
||||
init: mockInitWrapper,
|
||||
Z3Core: undefined,
|
||||
Z3LowLevel: undefined,
|
||||
}));
|
||||
jest.mock('./high-level', () => ({
|
||||
createApi: mockCreateApi,
|
||||
}));
|
||||
|
||||
import { init } from './node';
|
||||
|
||||
describe('node init', () => {
|
||||
beforeEach(() => {
|
||||
mockInitModule.mockReset();
|
||||
mockInitWrapper.mockReset();
|
||||
mockCreateApi.mockReset();
|
||||
});
|
||||
|
||||
it('passes module overrides to the low-level initializer', async () => {
|
||||
const locateFile = jest.fn((file: string) => `npm:z3-solver/build/${file}`);
|
||||
const lowLevel = { Z3: { low: true }, em: { module: true } };
|
||||
const highLevel = { Context: jest.fn() };
|
||||
mockInitWrapper.mockResolvedValue(lowLevel);
|
||||
mockCreateApi.mockReturnValue(highLevel);
|
||||
|
||||
const api = await init({ locateFile });
|
||||
|
||||
expect(mockInitWrapper).toHaveBeenCalledWith(mockInitModule, { locateFile });
|
||||
expect(mockCreateApi).toHaveBeenCalledWith(lowLevel.Z3, lowLevel.em);
|
||||
expect(api).toEqual({ ...lowLevel, ...highLevel });
|
||||
});
|
||||
});
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
import initModule = require('./z3-built');
|
||||
|
||||
import { createApi, Z3HighLevel } from './high-level';
|
||||
import { init as initWrapper, Z3LowLevel } from './low-level';
|
||||
import { init as initWrapper, Z3LowLevel, Z3ModuleOverrides } from './low-level';
|
||||
export * from './high-level/types';
|
||||
export { Z3Core, Z3LowLevel } from './low-level';
|
||||
export * from './low-level/types.__GENERATED__';
|
||||
|
|
@ -29,10 +29,17 @@ export * from './low-level/types.__GENERATED__';
|
|||
*
|
||||
* console.log(`x=${model.get(x)}, y=${model.get(y)}`);
|
||||
* // x=0, y=12
|
||||
*
|
||||
* // Deno users can provide an Emscripten locateFile hook to load the wasm
|
||||
* // through npm's asset resolution instead of filesystem reads.
|
||||
* // const api = await init({
|
||||
* // locateFile: (file, _prefix): string =>
|
||||
* // import.meta.resolve(`npm:z3-solver/build/${file}`), // _prefix is unused here
|
||||
* // });
|
||||
* ```
|
||||
* @category Global */
|
||||
export async function init(): Promise<Z3HighLevel & Z3LowLevel> {
|
||||
const lowLevel = await initWrapper(initModule);
|
||||
export async function init(moduleOverrides: Z3ModuleOverrides = {}): Promise<Z3HighLevel & Z3LowLevel> {
|
||||
const lowLevel = await initWrapper(initModule, moduleOverrides);
|
||||
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||
return { ...lowLevel, ...highLevel };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,6 +320,20 @@ JLCXX_MODULE define_julia_module(jlcxx::Module &m)
|
|||
m.method("finite_set_map", &finite_set_map);
|
||||
m.method("finite_set_filter", &finite_set_filter);
|
||||
m.method("finite_set_range", &finite_set_range);
|
||||
m.method("empty_set", &empty_set);
|
||||
m.method("full_set", &full_set);
|
||||
m.method("set_add", &set_add);
|
||||
m.method("set_del", &set_del);
|
||||
m.method("set_union", &set_union);
|
||||
m.method("set_intersect", &set_intersect);
|
||||
m.method("set_difference", &set_difference);
|
||||
m.method("set_complement", &set_complement);
|
||||
m.method("set_member", &set_member);
|
||||
m.method("set_subset", &set_subset);
|
||||
m.method("linear_order", &linear_order);
|
||||
m.method("partial_order", &partial_order);
|
||||
m.method("piecewise_linear_order", &piecewise_linear_order);
|
||||
m.method("tree_order", &tree_order);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -629,7 +643,13 @@ JLCXX_MODULE define_julia_module(jlcxx::Module &m)
|
|||
.MM(context, string_sort)
|
||||
.MM(context, seq_sort)
|
||||
.MM(context, re_sort)
|
||||
.MM(context, char_sort)
|
||||
.MM(context, finite_set_sort)
|
||||
.method("set_sort", [](context &c, sort s) {
|
||||
Z3_sort r = Z3_mk_set_sort(c, s);
|
||||
c.check_error();
|
||||
return sort(c, r);
|
||||
})
|
||||
.method("array_sort", static_cast<sort (context::*)(sort, sort)>(&context::array_sort))
|
||||
.method("array_sort", static_cast<sort (context::*)(sort_vector const&, sort)>(&context::array_sort))
|
||||
.method("fpa_sort", static_cast<sort (context::*)(unsigned, unsigned)>(&context::fpa_sort))
|
||||
|
|
|
|||
|
|
@ -475,6 +475,7 @@ sig
|
|||
val substitute : expr -> expr list -> expr list -> expr
|
||||
val substitute_one : expr -> expr -> expr -> expr
|
||||
val substitute_vars : expr -> expr list -> expr
|
||||
val substitute_funs : expr -> FuncDecl.func_decl list -> expr list -> expr
|
||||
val translate : expr -> context -> expr
|
||||
val to_string : expr -> string
|
||||
val is_numeral : expr -> bool
|
||||
|
|
@ -537,6 +538,13 @@ end = struct
|
|||
let substitute_vars x to_ =
|
||||
Z3native.substitute_vars (gc x) x (List.length to_) to_
|
||||
|
||||
let substitute_funs x from to_ =
|
||||
let len = List.length from in
|
||||
if List.length to_ <> len then
|
||||
raise (Error "Argument sizes do not match")
|
||||
else
|
||||
Z3native.substitute_funs (gc x) x len from to_
|
||||
|
||||
let translate (x:expr) to_ctx =
|
||||
if gc x = to_ctx then
|
||||
x
|
||||
|
|
@ -587,6 +595,12 @@ struct
|
|||
let mk_eq = Z3native.mk_eq
|
||||
let mk_distinct ctx args = Z3native.mk_distinct ctx (List.length args) args
|
||||
|
||||
let mk_atmost ctx args k = Z3native.mk_atmost ctx (List.length args) args k
|
||||
let mk_atleast ctx args k = Z3native.mk_atleast ctx (List.length args) args k
|
||||
let mk_pble ctx args coeffs k = Z3native.mk_pble ctx (List.length args) args coeffs k
|
||||
let mk_pbge ctx args coeffs k = Z3native.mk_pbge ctx (List.length args) args coeffs k
|
||||
let mk_pbeq ctx args coeffs k = Z3native.mk_pbeq ctx (List.length args) args coeffs k
|
||||
|
||||
let get_bool_value x = lbool_of_int (Z3native.get_bool_value (gc x) x)
|
||||
|
||||
let is_bool x =
|
||||
|
|
@ -1283,6 +1297,9 @@ struct
|
|||
let mk_seq_contains = Z3native.mk_seq_contains
|
||||
let mk_seq_extract = Z3native.mk_seq_extract
|
||||
let mk_seq_replace = Z3native.mk_seq_replace
|
||||
let mk_seq_replace_all = Z3native.mk_seq_replace_all
|
||||
let mk_seq_replace_re = Z3native.mk_seq_replace_re
|
||||
let mk_seq_replace_re_all = Z3native.mk_seq_replace_re_all
|
||||
let mk_seq_at = Z3native.mk_seq_at
|
||||
let mk_seq_length = Z3native.mk_seq_length
|
||||
let mk_seq_nth = Z3native.mk_seq_nth
|
||||
|
|
@ -1308,6 +1325,7 @@ struct
|
|||
let mk_re_loop = Z3native.mk_re_loop
|
||||
let mk_re_intersect ctx args = Z3native.mk_re_intersect ctx (List.length args) args
|
||||
let mk_re_complement = Z3native.mk_re_complement
|
||||
let mk_re_diff = Z3native.mk_re_diff
|
||||
let mk_re_empty = Z3native.mk_re_empty
|
||||
let mk_re_full = Z3native.mk_re_full
|
||||
let mk_char = Z3native.mk_char
|
||||
|
|
@ -1336,6 +1354,15 @@ struct
|
|||
let mk_range = Z3native.mk_finite_set_range
|
||||
end
|
||||
|
||||
module SpecialRelation =
|
||||
struct
|
||||
let mk_linear_order = Z3native.mk_linear_order
|
||||
let mk_partial_order = Z3native.mk_partial_order
|
||||
let mk_piecewise_linear_order = Z3native.mk_piecewise_linear_order
|
||||
let mk_tree_order = Z3native.mk_tree_order
|
||||
let mk_transitive_closure = Z3native.mk_transitive_closure
|
||||
end
|
||||
|
||||
module FloatingPoint =
|
||||
struct
|
||||
module RoundingMode =
|
||||
|
|
|
|||
|
|
@ -531,6 +531,10 @@ sig
|
|||
For every [i] smaller than [num_exprs], the variable with de-Bruijn index [i] is replaced with term [to[i]]. *)
|
||||
val substitute_vars : Expr.expr -> Expr.expr list -> expr
|
||||
|
||||
(** Substitute every application of [from[i]] with [to[i]] in the expression.
|
||||
The [from] and [to] lists must have the same length. *)
|
||||
val substitute_funs : Expr.expr -> FuncDecl.func_decl list -> Expr.expr list -> expr
|
||||
|
||||
(** Translates (copies) the term to another context.
|
||||
@return A copy of the term which is associated with the other context *)
|
||||
val translate : Expr.expr -> context -> expr
|
||||
|
|
@ -632,6 +636,21 @@ sig
|
|||
(** Creates a [distinct] term. *)
|
||||
val mk_distinct : context -> Expr.expr list -> Expr.expr
|
||||
|
||||
(** Encodes p1 + p2 + ... + pn <= k. *)
|
||||
val mk_atmost : context -> Expr.expr list -> int -> Expr.expr
|
||||
|
||||
(** Encodes p1 + p2 + ... + pn >= k. *)
|
||||
val mk_atleast : context -> Expr.expr list -> int -> Expr.expr
|
||||
|
||||
(** Encodes k1*p1 + k2*p2 + ... + kn*pn <= k. *)
|
||||
val mk_pble : context -> Expr.expr list -> int list -> int -> Expr.expr
|
||||
|
||||
(** Encodes k1*p1 + k2*p2 + ... + kn*pn >= k. *)
|
||||
val mk_pbge : context -> Expr.expr list -> int list -> int -> Expr.expr
|
||||
|
||||
(** Encodes k1*p1 + k2*p2 + ... + kn*pn = k. *)
|
||||
val mk_pbeq : context -> Expr.expr list -> int list -> int -> Expr.expr
|
||||
|
||||
(** Indicates whether the expression is the true or false expression
|
||||
or something else (L_UNDEF). *)
|
||||
val get_bool_value : Expr.expr -> Z3enums.lbool
|
||||
|
|
@ -1968,9 +1987,22 @@ sig
|
|||
(** extract sub-sequence starting at index given by second argument and of length provided by third argument *)
|
||||
val mk_seq_extract : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** replace first occurrence of second argument by third *)
|
||||
(** [mk_seq_replace ctx seq target replacement] replaces the first occurrence
|
||||
of [target] within [seq] with [replacement]. *)
|
||||
val mk_seq_replace : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** [mk_seq_replace_all ctx seq target replacement] replaces all occurrences
|
||||
of [target] within [seq] with [replacement]. *)
|
||||
val mk_seq_replace_all : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** [mk_seq_replace_re ctx seq re replacement] replaces the first occurrence
|
||||
matching the regular expression [re] within [seq] with [replacement]. *)
|
||||
val mk_seq_replace_re : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** [mk_seq_replace_re_all ctx seq re replacement] replaces all occurrences
|
||||
matching the regular expression [re] within [seq] with [replacement]. *)
|
||||
val mk_seq_replace_re_all : context -> Expr.expr -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** a unit sequence at index provided by second argument *)
|
||||
val mk_seq_at : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
|
|
@ -2048,6 +2080,9 @@ sig
|
|||
(** the regular expression complement *)
|
||||
val mk_re_complement : context -> Expr.expr -> Expr.expr
|
||||
|
||||
(** the regular expression difference *)
|
||||
val mk_re_diff : context -> Expr.expr -> Expr.expr -> Expr.expr
|
||||
|
||||
(** the regular expression that accepts no sequences *)
|
||||
val mk_re_empty : context -> Sort.sort -> Expr.expr
|
||||
|
||||
|
|
@ -2121,6 +2156,31 @@ sig
|
|||
|
||||
end
|
||||
|
||||
(** Special relation constructors *)
|
||||
module SpecialRelation :
|
||||
sig
|
||||
(** Create a linear (total) order relation over the given sort.
|
||||
The [id] parameter distinguishes multiple linear orders over the same sort. *)
|
||||
val mk_linear_order : context -> Sort.sort -> int -> FuncDecl.func_decl
|
||||
|
||||
(** Create a partial order relation over the given sort.
|
||||
The [id] parameter distinguishes multiple partial orders over the same sort. *)
|
||||
val mk_partial_order : context -> Sort.sort -> int -> FuncDecl.func_decl
|
||||
|
||||
(** Create a piecewise linear order relation over the given sort.
|
||||
The [id] parameter distinguishes multiple piecewise linear orders over the same sort. *)
|
||||
val mk_piecewise_linear_order : context -> Sort.sort -> int -> FuncDecl.func_decl
|
||||
|
||||
(** Create a tree order relation over the given sort.
|
||||
The [id] parameter distinguishes multiple tree orders over the same sort. *)
|
||||
val mk_tree_order : context -> Sort.sort -> int -> FuncDecl.func_decl
|
||||
|
||||
(** Create the transitive closure of a binary relation.
|
||||
The resulting relation is recursive. *)
|
||||
val mk_transitive_closure : context -> FuncDecl.func_decl -> FuncDecl.func_decl
|
||||
|
||||
end
|
||||
|
||||
(** Floating-Point Arithmetic *)
|
||||
module FloatingPoint :
|
||||
sig
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ class bdist_wheel(_bdist_wheel):
|
|||
("linux", "x86_64"): "linux_x86_64",
|
||||
("linux", "aarch64"): "linux_aarch64",
|
||||
('linux', "riscv64"): "linux_riscv64",
|
||||
("linux", "loongarch64"): "linux_loongarch64",
|
||||
# windows arm64 is not supported by pypi yet
|
||||
("win", "x64"): "win_amd64",
|
||||
("win", "x86"): "win32",
|
||||
|
|
|
|||
|
|
@ -5612,6 +5612,20 @@ class Datatype:
|
|||
"""
|
||||
return CreateDatatypes([self])[0]
|
||||
|
||||
def create_polymorphic(self, type_params):
|
||||
"""Create a polymorphic Z3 datatype with explicit type variables.
|
||||
|
||||
`type_params` is a list of type variables created with `DeclareTypeVar`.
|
||||
Constructor field sorts may reference these type variables.
|
||||
Self-recursive fields may reference this datatype directly.
|
||||
|
||||
>>> A = DeclareTypeVar('A')
|
||||
>>> Pair = Datatype('Pair')
|
||||
>>> Pair.declare('pair', ('fst', A), ('snd', A))
|
||||
>>> Pair = Pair.create_polymorphic([A])
|
||||
"""
|
||||
return CreatePolymorphicDatatype(self, type_params)
|
||||
|
||||
|
||||
class ScopedConstructor:
|
||||
"""Auxiliary object used to create Z3 datatypes."""
|
||||
|
|
@ -5733,6 +5747,76 @@ def CreateDatatypes(*ds):
|
|||
return tuple(result)
|
||||
|
||||
|
||||
def CreatePolymorphicDatatype(d, type_params):
|
||||
"""Create a single polymorphic Z3 datatype with explicit type parameters.
|
||||
|
||||
`d` is a `Datatype` helper object whose constructors have been declared.
|
||||
`type_params` is a list of type variables created with `DeclareTypeVar`.
|
||||
Constructor field sorts may reference these type variables, and self-recursive
|
||||
fields may reference `d` directly.
|
||||
|
||||
>>> A = DeclareTypeVar('A')
|
||||
>>> Pair = Datatype('Pair')
|
||||
>>> Pair.declare('pair', ('fst', A), ('snd', A))
|
||||
>>> Pair = CreatePolymorphicDatatype(Pair, [A])
|
||||
"""
|
||||
if z3_debug():
|
||||
_z3_assert(isinstance(d, Datatype), "Datatype expected")
|
||||
_z3_assert(d.constructors != [], "Non-empty Datatype expected")
|
||||
ctx = d.ctx
|
||||
name = to_symbol(d.name, ctx)
|
||||
num_params = len(type_params)
|
||||
params_arr = (Sort * num_params)()
|
||||
for i, p in enumerate(type_params):
|
||||
if z3_debug():
|
||||
_z3_assert(is_sort(p), "Z3 sort expected for type parameter")
|
||||
params_arr[i] = p.ast
|
||||
num_cs = len(d.constructors)
|
||||
cs = (Constructor * num_cs)()
|
||||
to_delete = []
|
||||
for j in range(num_cs):
|
||||
c = d.constructors[j]
|
||||
cname = to_symbol(c[0], ctx)
|
||||
rname = to_symbol(c[1], ctx)
|
||||
fs = c[2]
|
||||
num_fs = len(fs)
|
||||
fnames = (Symbol * num_fs)()
|
||||
sorts = (Sort * num_fs)()
|
||||
refs = (ctypes.c_uint * num_fs)()
|
||||
for k in range(num_fs):
|
||||
fname = fs[k][0]
|
||||
ftype = fs[k][1]
|
||||
fnames[k] = to_symbol(fname, ctx)
|
||||
if isinstance(ftype, Datatype):
|
||||
if z3_debug():
|
||||
_z3_assert(ftype is d, "Only self-recursive references are supported in polymorphic datatypes. Use CreateDatatypes for mutually recursive datatypes.")
|
||||
sorts[k] = None
|
||||
refs[k] = 0
|
||||
else:
|
||||
if z3_debug():
|
||||
_z3_assert(is_sort(ftype), "Z3 sort expected")
|
||||
sorts[k] = ftype.ast
|
||||
refs[k] = 0
|
||||
cs[j] = Z3_mk_constructor(ctx.ref(), cname, rname, num_fs, fnames, sorts, refs)
|
||||
to_delete.append(ScopedConstructor(cs[j], ctx))
|
||||
out = Z3_mk_polymorphic_datatype(ctx.ref(), name, num_params, params_arr, num_cs, cs)
|
||||
dref = DatatypeSortRef(out, ctx)
|
||||
num_cs_actual = dref.num_constructors()
|
||||
for j in range(num_cs_actual):
|
||||
cref = dref.constructor(j)
|
||||
cref_name = cref.name()
|
||||
cref_arity = cref.arity()
|
||||
if cref_arity == 0:
|
||||
cref = cref()
|
||||
setattr(dref, cref_name, cref)
|
||||
rref = dref.recognizer(j)
|
||||
setattr(dref, "is_" + cref_name, rref)
|
||||
for k in range(cref_arity):
|
||||
aref = dref.accessor(j, k)
|
||||
setattr(dref, aref.name(), aref)
|
||||
return dref
|
||||
|
||||
|
||||
class DatatypeSortRef(SortRef):
|
||||
"""Datatype sorts."""
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ array_decl_plugin::array_decl_plugin():
|
|||
m_set_complement_sym("complement"),
|
||||
m_set_subset_sym("subset"),
|
||||
m_array_ext_sym("array-ext"),
|
||||
m_as_array_sym("as-array") {
|
||||
m_as_array_sym("as-array"),
|
||||
m_choice_sym("choice") {
|
||||
}
|
||||
|
||||
#define ARRAY_SORT_STR "Array"
|
||||
|
|
@ -433,6 +434,20 @@ func_decl * array_decl_plugin::mk_as_array(func_decl * f) {
|
|||
return m_manager->mk_const_decl(m_as_array_sym, s, info);
|
||||
}
|
||||
|
||||
func_decl* array_decl_plugin::mk_choice(unsigned arity, sort* const* domain) {
|
||||
if (arity != 1) {
|
||||
m_manager->raise_exception("choice takes one argument");
|
||||
return nullptr;
|
||||
}
|
||||
sort* s = domain[0];
|
||||
if (!is_array_sort(s) || get_array_arity(s) != 1 || !m_manager->is_bool(get_array_range(s))) {
|
||||
m_manager->raise_exception("choice expects an argument with sort (Array T Bool)");
|
||||
return nullptr;
|
||||
}
|
||||
return m_manager->mk_func_decl(m_choice_sym, arity, domain, get_array_domain(s, 0),
|
||||
func_decl_info(m_family_id, OP_CHOICE));
|
||||
}
|
||||
|
||||
|
||||
func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
|
|
@ -501,6 +516,8 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
|
|||
func_decl * f = to_func_decl(parameters[0].get_ast());
|
||||
return mk_as_array(f);
|
||||
}
|
||||
case OP_CHOICE:
|
||||
return mk_choice(arity, domain);
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
@ -529,6 +546,7 @@ void array_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol con
|
|||
op_names.push_back(builtin_name("complement",OP_SET_COMPLEMENT));
|
||||
op_names.push_back(builtin_name("subset",OP_SET_SUBSET));
|
||||
op_names.push_back(builtin_name("as-array", OP_AS_ARRAY));
|
||||
op_names.push_back(builtin_name("choice", OP_CHOICE));
|
||||
op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT));
|
||||
|
||||
#if 0
|
||||
|
|
@ -655,4 +673,3 @@ func_decl* array_util::mk_array_ext(sort *domain, unsigned i) {
|
|||
parameter p(i);
|
||||
return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ enum array_op_kind {
|
|||
OP_SET_COMPLEMENT,
|
||||
OP_SET_SUBSET,
|
||||
OP_AS_ARRAY, // used for model construction
|
||||
OP_CHOICE,
|
||||
LAST_ARRAY_OP
|
||||
};
|
||||
|
||||
|
|
@ -79,6 +80,7 @@ class array_decl_plugin : public decl_plugin {
|
|||
symbol m_set_subset_sym;
|
||||
symbol m_array_ext_sym;
|
||||
symbol m_as_array_sym;
|
||||
symbol m_choice_sym;
|
||||
|
||||
bool check_set_arguments(unsigned arity, sort * const * domain);
|
||||
|
||||
|
|
@ -106,6 +108,8 @@ class array_decl_plugin : public decl_plugin {
|
|||
|
||||
func_decl * mk_as_array(func_decl * f);
|
||||
|
||||
func_decl * mk_choice(unsigned arity, sort* const* domain);
|
||||
|
||||
bool is_array_sort(sort* s) const;
|
||||
public:
|
||||
array_decl_plugin();
|
||||
|
|
@ -164,6 +168,7 @@ public:
|
|||
bool is_difference(expr* n) const { return is_app_of(n, m_fid, OP_SET_DIFFERENCE); }
|
||||
bool is_complement(expr* n) const { return is_app_of(n, m_fid, OP_SET_COMPLEMENT); }
|
||||
bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); }
|
||||
bool is_choice(expr* n) const { return is_app_of(n, m_fid, OP_CHOICE); }
|
||||
bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); }
|
||||
bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); }
|
||||
bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); }
|
||||
|
|
@ -172,6 +177,7 @@ public:
|
|||
bool is_union(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_UNION); }
|
||||
bool is_intersect(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_INTERSECT); }
|
||||
bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); }
|
||||
bool is_choice(func_decl* f) const { return is_decl_of(f, m_fid, OP_CHOICE); }
|
||||
bool is_default(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_DEFAULT); }
|
||||
bool is_default(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_DEFAULT); }
|
||||
bool is_subset(expr const* n) const { return is_app_of(n, m_fid, OP_SET_SUBSET); }
|
||||
|
|
@ -308,6 +314,10 @@ public:
|
|||
return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, nullptr, nullptr);
|
||||
}
|
||||
|
||||
app* mk_choice(expr* p) const {
|
||||
return m_manager.mk_app(m_fid, OP_CHOICE, p);
|
||||
}
|
||||
|
||||
sort* get_array_range_rec(sort* s) {
|
||||
while (is_array(s)) {
|
||||
s = get_array_range(s);
|
||||
|
|
@ -317,5 +327,3 @@ public:
|
|||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -242,21 +242,14 @@ func_decl_info::func_decl_info(family_id family_id, decl_kind k, unsigned num_pa
|
|||
m_injective(false),
|
||||
m_idempotent(false),
|
||||
m_skolem(false),
|
||||
m_lambda(false),
|
||||
m_polymorphic(false) {
|
||||
}
|
||||
|
||||
bool func_decl_info::operator==(func_decl_info const & info) const {
|
||||
return decl_info::operator==(info) &&
|
||||
m_left_assoc == info.m_left_assoc &&
|
||||
m_right_assoc == info.m_right_assoc &&
|
||||
m_flat_associative == info.m_flat_associative &&
|
||||
m_commutative == info.m_commutative &&
|
||||
m_chainable == info.m_chainable &&
|
||||
m_pairwise == info.m_pairwise &&
|
||||
m_injective == info.m_injective &&
|
||||
m_skolem == info.m_skolem &&
|
||||
m_lambda == info.m_lambda;
|
||||
return decl_info::operator==(info) && m_left_assoc == info.m_left_assoc && m_right_assoc == info.m_right_assoc &&
|
||||
m_flat_associative == info.m_flat_associative && m_commutative == info.m_commutative &&
|
||||
m_chainable == info.m_chainable && m_pairwise == info.m_pairwise && m_injective == info.m_injective &&
|
||||
m_skolem == info.m_skolem;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, func_decl_info const & info) {
|
||||
|
|
@ -270,7 +263,6 @@ std::ostream & operator<<(std::ostream & out, func_decl_info const & info) {
|
|||
if (info.is_injective()) out << " :injective ";
|
||||
if (info.is_idempotent()) out << " :idempotent ";
|
||||
if (info.is_skolem()) out << " :skolem ";
|
||||
if (info.is_lambda()) out << " :lambda ";
|
||||
if (info.is_polymorphic()) out << " :polymorphic ";
|
||||
return out;
|
||||
}
|
||||
|
|
@ -1625,19 +1617,6 @@ bool ast_manager::are_distinct(expr* a, expr* b) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void ast_manager::add_lambda_def(func_decl* f, quantifier* q) {
|
||||
TRACE(model, tout << "add lambda def " << mk_pp(q, *this) << "\n");
|
||||
m_lambda_defs.insert(f, q);
|
||||
f->get_info()->set_lambda(true);
|
||||
inc_ref(q);
|
||||
}
|
||||
|
||||
quantifier* ast_manager::is_lambda_def(func_decl* f) {
|
||||
if (f->get_info() && f->get_info()->is_lambda())
|
||||
return m_lambda_defs[f];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void ast_manager::register_plugin(family_id id, decl_plugin * plugin) {
|
||||
SASSERT(m_plugins.get(id, 0) == 0);
|
||||
|
|
@ -1670,7 +1649,7 @@ bool ast_manager::slow_not_contains(ast const * n) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
static unsigned s_count = 0;
|
||||
|
||||
static void track_id(ast_manager& m, ast* n, unsigned id) {
|
||||
|
|
@ -1832,10 +1811,6 @@ void ast_manager::delete_node(ast * n) {
|
|||
m_poly_roots.erase(f);
|
||||
if (f->m_info != nullptr) {
|
||||
func_decl_info * info = f->get_info();
|
||||
if (info->is_lambda()) {
|
||||
push_dec_ref(m_lambda_defs[f]);
|
||||
m_lambda_defs.remove(f);
|
||||
}
|
||||
info->del_eh(*this);
|
||||
dealloc(info);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,7 +404,6 @@ struct func_decl_info : public decl_info {
|
|||
bool m_injective:1;
|
||||
bool m_idempotent:1;
|
||||
bool m_skolem:1;
|
||||
bool m_lambda:1;
|
||||
bool m_polymorphic:1;
|
||||
|
||||
func_decl_info(family_id family_id = null_family_id, decl_kind k = null_decl_kind, unsigned num_parameters = 0, parameter const * parameters = nullptr);
|
||||
|
|
@ -419,7 +418,6 @@ struct func_decl_info : public decl_info {
|
|||
bool is_injective() const { return m_injective; }
|
||||
bool is_idempotent() const { return m_idempotent; }
|
||||
bool is_skolem() const { return m_skolem; }
|
||||
bool is_lambda() const { return m_lambda; }
|
||||
bool is_polymorphic() const { return m_polymorphic; }
|
||||
|
||||
void set_associative(bool flag = true) { m_left_assoc = flag; m_right_assoc = flag; }
|
||||
|
|
@ -432,7 +430,6 @@ struct func_decl_info : public decl_info {
|
|||
void set_injective(bool flag = true) { m_injective = flag; }
|
||||
void set_idempotent(bool flag = true) { m_idempotent = flag; }
|
||||
void set_skolem(bool flag = true) { m_skolem = flag; }
|
||||
void set_lambda(bool flag = true) { m_lambda = flag; }
|
||||
void set_polymorphic(bool flag = true) { m_polymorphic = flag; }
|
||||
|
||||
bool operator==(func_decl_info const & info) const;
|
||||
|
|
@ -661,7 +658,6 @@ public:
|
|||
bool is_pairwise() const { return get_info() != nullptr && get_info()->is_pairwise(); }
|
||||
bool is_injective() const { return get_info() != nullptr && get_info()->is_injective(); }
|
||||
bool is_skolem() const { return get_info() != nullptr && get_info()->is_skolem(); }
|
||||
bool is_lambda() const { return get_info() != nullptr && get_info()->is_lambda(); }
|
||||
bool is_idempotent() const { return get_info() != nullptr && get_info()->is_idempotent(); }
|
||||
bool is_polymorphic() const { return get_info() != nullptr && get_info()->is_polymorphic(); }
|
||||
unsigned get_arity() const { return m_arity; }
|
||||
|
|
@ -857,7 +853,8 @@ public:
|
|||
enum quantifier_kind {
|
||||
forall_k,
|
||||
exists_k,
|
||||
lambda_k
|
||||
lambda_k,
|
||||
choice_k
|
||||
};
|
||||
|
||||
class quantifier : public expr {
|
||||
|
|
@ -1512,7 +1509,6 @@ protected:
|
|||
proof_gen_mode m_proof_mode;
|
||||
bool m_int_real_coercions; // If true, use hack that automatically introduces to_int/to_real when needed.
|
||||
ast_table m_ast_table;
|
||||
obj_map<func_decl, quantifier*> m_lambda_defs;
|
||||
id_gen m_expr_id_gen;
|
||||
id_gen m_decl_id_gen;
|
||||
sort * m_bool_sort;
|
||||
|
|
@ -1642,15 +1638,7 @@ public:
|
|||
bool are_distinct(expr * a, expr * b) const;
|
||||
|
||||
bool contains(ast * a) const { return m_ast_table.contains(a); }
|
||||
|
||||
bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; }
|
||||
void add_lambda_def(func_decl* f, quantifier* q);
|
||||
quantifier* is_lambda_def(func_decl* f);
|
||||
quantifier* is_lambda_def(app* e) { return is_lambda_def(e->get_decl()); }
|
||||
obj_map<func_decl, quantifier*> const& lambda_defs() const { return m_lambda_defs; }
|
||||
|
||||
symbol const& lambda_def_qid() const { return m_lambda_def; }
|
||||
|
||||
|
||||
unsigned get_num_asts() const { return m_ast_table.size(); }
|
||||
|
||||
void debug_ref_count() { m_debug_ref_count = true; }
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ Revision History:
|
|||
--*/
|
||||
#include "ast/ast.h"
|
||||
|
||||
#define check_symbol(S1,S2) if (S1 != S2) return lt(S1,S2)
|
||||
#define check_value(V1,V2) if (V1 != V2) return V1 < V2
|
||||
#define check_bool(B1,B2) if (B1 != B2) return !B1 && B2
|
||||
#define check_ptr(P1,P2) if (!P1 && P2) return true; if (P1 && !P2) return false
|
||||
#define check_ast(T1,T2) if (T1 != T2) { n1 = T1; n2 = T2; goto start; }
|
||||
#define check_zstring(S1, S2) if (S1 != S2) return S1 < S2
|
||||
#define check_symbol(S1,S2) if ((S1) != (S2)) return lt((S1),(S2))
|
||||
#define check_value(V1,V2) if ((V1) != (V2)) return (V1) < (V2)
|
||||
#define check_bool(B1,B2) if ((B1) != (B2)) return !(B1) && (B2)
|
||||
#define check_ptr(P1,P2) if (!(P1) && (P2)) return true; if ((P1) && !(P2)) return false
|
||||
#define check_ast(T1,T2) if ((T1) != (T2)) { n1 = (T1); n2 = (T2); goto start; }
|
||||
#define check_zstring(S1, S2) if ((S1) != (S2)) return (S1) < (S2)
|
||||
|
||||
#define check_parameter(p1, p2) { \
|
||||
check_value(p1.get_kind(), p2.get_kind()); \
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ private:
|
|||
|
||||
void pp_atomic_step(const expr * e) {
|
||||
unsigned id = get_id(e);
|
||||
m_out << "node_" << id << " [shape=box,color=\"yellow\",style=\"filled\",label=\"" << label_of_expr(e) << "\"] ;" << std::endl;
|
||||
m_out << "node_" << id << " [shape=box,color=\"yellow\",style=\"filled\",label=\"" << label_of_expr(e) << "\"] ;" << '\n';
|
||||
}
|
||||
|
||||
void pp_step(const proof * p) {
|
||||
|
|
@ -91,7 +91,7 @@ private:
|
|||
m_first ? (m_first=false,"color=\"red\"") : num_parents==0 ? "color=\"yellow\"": "";
|
||||
m_out << "node_" << id <<
|
||||
" [shape=box,style=\"filled\",label=\"" << label_of_expr(p_res) << "\""
|
||||
<< color << "]" << std::endl;
|
||||
<< color << "]" << '\n';
|
||||
// now print edges to parents (except last one, which is the result)
|
||||
std::string label = p->get_decl()->get_name().str();
|
||||
for (unsigned i = 0 ; i < num_parents; ++i) {
|
||||
|
|
@ -99,7 +99,7 @@ private:
|
|||
// explore parent, also print a link to it
|
||||
push_term(to_app(parent));
|
||||
m_out << "node_" << id << " -> " << "node_" << get_id((expr*)parent)
|
||||
<< "[label=\"" << label << "\"];" << std::endl;;
|
||||
<< "[label=\"" << label << "\"];" << '\n';
|
||||
}
|
||||
} else {
|
||||
pp_atomic_step(p);
|
||||
|
|
@ -120,11 +120,11 @@ private:
|
|||
|
||||
// main printer
|
||||
std::ostream & ast_pp_dot::pp(std::ostream & out) const {
|
||||
out << "digraph proof { " << std::endl;
|
||||
out << "digraph proof { " << '\n';
|
||||
ast_pp_dot_st pp_st(this, out);
|
||||
pp_st.push_term(m_pr);
|
||||
pp_st.pp_loop();
|
||||
out << std::endl << " } " << std::endl << std::flush;
|
||||
out << '\n' << " } " << '\n' << std::flush;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -733,7 +733,8 @@ public:
|
|||
m_AUFLIRA("AUFLIRA"),
|
||||
// It's much easier to read those testcases with that.
|
||||
m_no_lets(no_lets),
|
||||
m_simplify_implies(simplify_implies)
|
||||
m_simplify_implies(simplify_implies),
|
||||
m_top(nullptr)
|
||||
{
|
||||
m_basic_fid = m.get_basic_family_id();
|
||||
m_label_fid = m.mk_family_id("label");
|
||||
|
|
|
|||
|
|
@ -181,20 +181,12 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) {
|
|||
new_fi.set_injective(fi->is_injective());
|
||||
new_fi.set_skolem(fi->is_skolem());
|
||||
new_fi.set_idempotent(fi->is_idempotent());
|
||||
new_fi.set_lambda(fi->is_lambda());
|
||||
|
||||
new_f = m_to_manager.mk_func_decl(f->get_name(),
|
||||
f->get_arity(),
|
||||
new_domain,
|
||||
new_range,
|
||||
new_fi);
|
||||
|
||||
if (new_fi.is_lambda()) {
|
||||
quantifier* q = from().is_lambda_def(f);
|
||||
ast_translation tr(from(), to());
|
||||
quantifier* new_q = tr(q);
|
||||
to().add_lambda_def(new_f, new_q);
|
||||
}
|
||||
}
|
||||
TRACE(ast_translation,
|
||||
tout << f->get_name() << " "; if (fi) tout << *fi; tout << "\n";
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ expr * mk_and(ast_manager & m, unsigned num_args, expr * const * args) {
|
|||
}
|
||||
|
||||
app* mk_and(ast_manager & m, unsigned num_args, app * const * args) {
|
||||
return to_app(mk_and(m, num_args, (expr* const*) args));
|
||||
return to_app(mk_and(m, num_args, reinterpret_cast<expr* const*>(args)));
|
||||
}
|
||||
|
||||
expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) {
|
||||
|
|
|
|||
|
|
@ -783,6 +783,9 @@ void bv_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const
|
|||
op_names.push_back(builtin_name("rotate_left",OP_ROTATE_LEFT));
|
||||
op_names.push_back(builtin_name("rotate_right",OP_ROTATE_RIGHT));
|
||||
op_names.push_back(builtin_name("bit2bool", OP_BIT2BOOL));
|
||||
op_names.push_back(builtin_name("ubv_to_int", OP_UBV2INT));
|
||||
op_names.push_back(builtin_name("sbv_to_int", OP_SBV2INT));
|
||||
op_names.push_back(builtin_name("int_to_bv", OP_INT2BV));
|
||||
|
||||
if (logic == symbol::null || logic == symbol("ALL") || logic == "QF_FD" || logic == "HORN") {
|
||||
op_names.push_back(builtin_name("bvumul_noovfl",OP_BUMUL_NO_OVFL));
|
||||
|
|
@ -804,11 +807,10 @@ void bv_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const
|
|||
op_names.push_back(builtin_name("ext_rotate_left",OP_EXT_ROTATE_LEFT));
|
||||
op_names.push_back(builtin_name("ext_rotate_right",OP_EXT_ROTATE_RIGHT));
|
||||
op_names.push_back(builtin_name("int2bv",OP_INT2BV));
|
||||
op_names.push_back(builtin_name("int_to_bv",OP_INT2BV));
|
||||
|
||||
op_names.push_back(builtin_name("bv2int",OP_UBV2INT));
|
||||
op_names.push_back(builtin_name("bv2nat",OP_UBV2INT));
|
||||
op_names.push_back(builtin_name("ubv_to_int",OP_UBV2INT));
|
||||
op_names.push_back(builtin_name("sbv_to_int",OP_SBV2INT));
|
||||
|
||||
op_names.push_back(builtin_name("mkbv",OP_MKBV));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ namespace euf {
|
|||
// Instructions
|
||||
//
|
||||
// ------------------------------------
|
||||
typedef enum {
|
||||
typedef enum : uint8_t {
|
||||
INIT1=0, INIT2, INIT3, INIT4, INIT5, INIT6, INITN, INITAC,
|
||||
BIND1, BIND2, BIND3, BIND4, BIND5, BIND6, BINDN,
|
||||
YIELD1, YIELD2, YIELD3, YIELD4, YIELD5, YIELD6, YIELDN,
|
||||
|
|
@ -239,6 +239,7 @@ namespace euf {
|
|||
unsigned short m_num_args;
|
||||
unsigned m_ireg;
|
||||
unsigned m_oreg;
|
||||
unsigned m_curr_generation;
|
||||
};
|
||||
|
||||
struct get_cgr : public instruction {
|
||||
|
|
@ -1926,28 +1927,38 @@ namespace euf {
|
|||
m_max_generation = std::max(m_max_generation, n->generation());
|
||||
}
|
||||
|
||||
void get_f_app(func_decl* lbl, unsigned num_expected_args, enode* curr, enode*& matching_cgr, enode*& min_gen_match) {
|
||||
if (curr->get_decl() == lbl && curr->num_args() == num_expected_args) {
|
||||
if (curr->is_cgr() && !matching_cgr)
|
||||
matching_cgr = curr;
|
||||
if (!min_gen_match || min_gen_match->generation() > curr->generation())
|
||||
min_gen_match = curr;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to provide the number of expected arguments because we have flat-assoc applications such as +.
|
||||
// Flat-assoc applications may have arbitrary number of arguments.
|
||||
enode * get_first_f_app(func_decl * lbl, unsigned num_expected_args, enode * first) {
|
||||
enode *matching_cgr = nullptr, *min_gen_match = nullptr;
|
||||
for (enode* curr : euf::enode_class(first)) {
|
||||
if (curr->get_decl() == lbl && curr->is_cgr() && curr->num_args() == num_expected_args) {
|
||||
update_max_generation(curr, first);
|
||||
return curr;
|
||||
}
|
||||
get_f_app(lbl, num_expected_args, curr, matching_cgr, min_gen_match);
|
||||
curr = curr->get_next();
|
||||
}
|
||||
return nullptr;
|
||||
if (matching_cgr)
|
||||
update_max_generation(min_gen_match, first);
|
||||
return matching_cgr;
|
||||
}
|
||||
|
||||
enode * get_next_f_app(func_decl * lbl, unsigned num_expected_args, enode * first, enode * curr) {
|
||||
curr = curr->get_next();
|
||||
enode *matching_cgr = nullptr, *min_gen_match = nullptr;
|
||||
while (curr != first) {
|
||||
if (curr->get_decl() == lbl && curr->is_cgr() && curr->num_args() == num_expected_args) {
|
||||
update_max_generation(curr, first);
|
||||
return curr;
|
||||
}
|
||||
get_f_app(lbl, num_expected_args, curr, matching_cgr, min_gen_match);
|
||||
curr = curr->get_next();
|
||||
}
|
||||
return nullptr;
|
||||
if (matching_cgr)
|
||||
update_max_generation(min_gen_match, first);
|
||||
return matching_cgr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2563,6 +2574,7 @@ namespace euf {
|
|||
m_backtrack_stack[m_top].m_instr = m_pc; \
|
||||
m_backtrack_stack[m_top].m_old_max_generation = m_curr_max_generation; \
|
||||
m_backtrack_stack[m_top].m_curr = m_app; \
|
||||
const_cast<bind*>(static_cast<bind const*>(m_pc))->m_curr_generation = m_max_generation; \
|
||||
m_top++;
|
||||
|
||||
BIND_COMMON();
|
||||
|
|
@ -2829,7 +2841,8 @@ namespace euf {
|
|||
goto backtrack; \
|
||||
} \
|
||||
bp.m_curr = m_app; \
|
||||
TRACE(mam_int, tout << "bind next candidate:\n" << mk_ll_pp(m_app->get_expr(), m);); \
|
||||
m_max_generation = m_b->m_curr_generation; \
|
||||
TRACE(mam_int, tout << "bind next candidate:\n" << mk_ll_pp(m_app->get_expr(), m);); \
|
||||
m_oreg = m_b->m_oreg
|
||||
|
||||
BBIND_COMMON();
|
||||
|
|
@ -4059,4 +4072,4 @@ void euf::mam::ground_subterms(expr* e, ptr_vector<app>& ground) {
|
|||
|
||||
euf::mam* euf::mam::mk(euf::mam_solver& ctx, euf::on_binding_callback& em) {
|
||||
return alloc(mam_impl, ctx, em, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace euf {
|
|||
}
|
||||
|
||||
void ho_matcher::search() {
|
||||
IF_VERBOSE(1, display(verbose_stream()));
|
||||
IF_VERBOSE(10, display(verbose_stream()));
|
||||
|
||||
while (m.inc()) {
|
||||
// Q, B -> Q', B'. Push work on the backtrack stack and new work items
|
||||
|
|
@ -77,7 +77,7 @@ namespace euf {
|
|||
break;
|
||||
}
|
||||
|
||||
IF_VERBOSE(1, display(verbose_stream() << "ho_matcher: done\n"));
|
||||
IF_VERBOSE(10, display(verbose_stream() << "ho_matcher: done\n"));
|
||||
}
|
||||
|
||||
void ho_matcher::backtrack() {
|
||||
|
|
@ -92,7 +92,7 @@ namespace euf {
|
|||
while (!m_backtrack.empty()) {
|
||||
auto& wi = *m_backtrack.back();
|
||||
bool st = consume_work(wi);
|
||||
IF_VERBOSE(3, display(verbose_stream() << "ho_matcher::consume_work: " << wi.pat << " =?= " << wi.t << " -> " << (st?"true":"false") << "\n"););
|
||||
TRACE(ho_matching, display(tout << "ho_matcher::consume_work: " << mk_bounded_pp(wi.pat, m) << " =?= " << mk_bounded_pp(wi.t, m) << " -> " << (st?"true":"false") << "\n"););
|
||||
if (st) {
|
||||
if (m_goals.empty())
|
||||
m_on_match(m_subst);
|
||||
|
|
@ -110,7 +110,11 @@ namespace euf {
|
|||
}
|
||||
|
||||
lbool ho_matcher::are_equal(unsigned o1, expr* p, unsigned o2, expr* t) const {
|
||||
SASSERT(p->get_sort() == t->get_sort());
|
||||
if (p->get_sort() != t->get_sort()) {
|
||||
TRACE(ho_matching, tout << "sort mismatch: " << mk_pp(p, m) << " : " << mk_pp(p->get_sort(), m)
|
||||
<< " vs " << mk_pp(t, m) << " : " << mk_pp(t->get_sort(), m) << "\n";);
|
||||
return l_false;
|
||||
}
|
||||
if (o1 == o2 && p == t)
|
||||
return l_true;
|
||||
|
||||
|
|
@ -239,25 +243,19 @@ namespace euf {
|
|||
return r;
|
||||
}
|
||||
|
||||
// We assume that m_rewriter should produce
|
||||
// something amounting to weak-head normal form WHNF
|
||||
expr_ref ho_matcher::whnf_star(expr *e, unsigned offset) const {
|
||||
expr_ref r(e, m);
|
||||
while (true) {
|
||||
auto q = whnf(r, offset);
|
||||
if (q == r)
|
||||
return r;
|
||||
r = q;
|
||||
}
|
||||
}
|
||||
|
||||
void ho_matcher::reduce(match_goal& wi) {
|
||||
while (true) {
|
||||
expr_ref r = whnf(wi.pat, wi.pat_offset());
|
||||
if (r == wi.pat)
|
||||
break;
|
||||
IF_VERBOSE(3, verbose_stream() << "ho_matcher::reduce: " << wi.pat << " -> " << r << "\n";);
|
||||
wi.pat = r;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
expr_ref r = whnf(wi.t, wi.term_offset());
|
||||
if (r == wi.t)
|
||||
break;
|
||||
IF_VERBOSE(3, verbose_stream() << "ho_matcher::reduce: " << wi.t << " -> " << r << "\n";);
|
||||
wi.t = r;
|
||||
}
|
||||
wi.pat = whnf_star(wi.pat, wi.pat_offset());
|
||||
wi.t = whnf_star(wi.t, wi.term_offset());
|
||||
}
|
||||
|
||||
bool ho_matcher::consume_work(match_goal &wi) {
|
||||
|
|
@ -288,7 +286,6 @@ namespace euf {
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
// v >= offset
|
||||
// v - offset |-> t
|
||||
if (is_meta_var(p, wi.pat_offset()) && is_closed(t, 0, wi.term_offset())) {
|
||||
|
|
@ -299,7 +296,6 @@ namespace euf {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// N = \ x. T => ((shift1 N) x) = T
|
||||
if (is_lambda(t) && !is_lambda(p)) {
|
||||
auto q = to_quantifier(t);
|
||||
|
|
@ -318,6 +314,43 @@ namespace euf {
|
|||
return true;
|
||||
}
|
||||
|
||||
// \x . N = T => N = ((shift1 T) x)
|
||||
if (is_lambda(p) && !is_lambda(t)) {
|
||||
auto q = to_quantifier(p);
|
||||
auto p_body = q->get_expr();
|
||||
auto nd = q->get_num_decls();
|
||||
var_shifter vs(m);
|
||||
expr_ref r(m);
|
||||
vs(t, nd, r);
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(r);
|
||||
for (unsigned i = 0; i < nd; ++i)
|
||||
args.push_back(m.mk_var(nd - 1 - i, q->get_decl_sort(i)));
|
||||
r = m_array.mk_select(args);
|
||||
m_goals.push(wi.level, wi.term_offset() + nd, p_body, r);
|
||||
wi.set_done();
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// lambda x . p == lambda x . t
|
||||
//
|
||||
if (is_quantifier(p) && is_quantifier(t)) {
|
||||
auto qp = to_quantifier(p);
|
||||
auto qt = to_quantifier(t);
|
||||
unsigned pd = qp->get_num_decls();
|
||||
unsigned td = qt->get_num_decls();
|
||||
if (qp->get_kind() != qt->get_kind())
|
||||
return false;
|
||||
if (pd != td)
|
||||
return false;
|
||||
for (unsigned i = 0; i < pd; ++i)
|
||||
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());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Flex head unitary
|
||||
// H(pat) = t
|
||||
|
||||
|
|
@ -457,25 +490,7 @@ namespace euf {
|
|||
m_goals.push(wi.level, wi.term_offset(), tp->get_arg(i), ta->get_arg(i));
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// lambda x . p == lambda x . t
|
||||
//
|
||||
if (is_quantifier(p) && is_quantifier(t)) {
|
||||
auto qp = to_quantifier(p);
|
||||
auto qt = to_quantifier(t);
|
||||
unsigned pd = qp->get_num_decls();
|
||||
unsigned td = qt->get_num_decls();
|
||||
if (qp->get_kind() != qt->get_kind())
|
||||
return false;
|
||||
if (pd != td)
|
||||
return false;
|
||||
for (unsigned i = 0; i < pd; ++i)
|
||||
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());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -488,8 +503,7 @@ namespace euf {
|
|||
uint_set vars;
|
||||
while (m_array.is_select(p)) {
|
||||
auto a = to_app(p);
|
||||
for (unsigned i = 1; i < a->get_num_args(); ++i) {
|
||||
auto arg = a->get_arg(i);
|
||||
for (auto arg : *a) {
|
||||
if (!is_bound_var(arg, offset))
|
||||
return false;
|
||||
auto idx = to_var(arg)->get_idx();
|
||||
|
|
@ -549,15 +563,12 @@ namespace euf {
|
|||
}
|
||||
expr_ref_vector pat2bound(m);
|
||||
for (auto a : pats) {
|
||||
unsigned sz = a->get_num_args();
|
||||
for (unsigned i = 1; i < sz; ++i) {
|
||||
auto arg = a->get_arg(i);
|
||||
for (auto arg : *a) {
|
||||
SASSERT(is_bound_var(arg, offset));
|
||||
auto idx = to_var(arg)->get_idx();
|
||||
pat2bound.reserve(idx + 1);
|
||||
pat2bound[idx] = m.mk_var(--num_bound, arg->get_sort());
|
||||
}
|
||||
p1 = a->get_arg(0);
|
||||
}
|
||||
}
|
||||
var_subst sub(m, false);
|
||||
expr_ref lam = sub(t, pat2bound);
|
||||
|
|
@ -575,7 +586,7 @@ namespace euf {
|
|||
|
||||
//
|
||||
// keep track of number of internal scopes and offset to non-capture variables.
|
||||
// a variable is captured if it's index is in the interval [scopes, offset[.
|
||||
// a variable is captured if its index is in the interval [scopes, offset[.
|
||||
//
|
||||
bool ho_matcher::is_closed(expr* v, unsigned scopes, unsigned offset) const {
|
||||
if (is_ground(v))
|
||||
|
|
@ -630,49 +641,59 @@ namespace euf {
|
|||
void ho_matcher::add_binding(var* v, unsigned offset, expr* t) {
|
||||
SASSERT(v->get_idx() >= offset);
|
||||
m_subst.set(v->get_idx() - offset, t);
|
||||
IF_VERBOSE(1, verbose_stream() << "ho_matcher::add_binding: v" << v->get_idx() - offset << " -> " << mk_pp(t, m) << "\n";);
|
||||
SASSERT(v->get_sort() == t->get_sort());
|
||||
TRACE(ho_matching, tout << "ho_matcher::add_binding: v" << v->get_idx() - offset << " -> " << mk_pp(t, m) << "\n";);
|
||||
m_trail.push(undo_set(m_subst, v->get_idx() - offset));
|
||||
}
|
||||
|
||||
|
||||
std::pair<quantifier*, app*> ho_matcher::compile_ho_pattern(quantifier* q, app* p) {
|
||||
app* p1 = nullptr;
|
||||
if (m_pat2hopat.find(p, p)) {
|
||||
q = m_q2hoq[q];
|
||||
return { q, p };
|
||||
quantifier *q1 = nullptr;
|
||||
if (m_pat2hopat.find(p, p1) && m_q2hoq.find(q, q1)) {
|
||||
return { q1, p1 };
|
||||
}
|
||||
auto is_ho = any_of(subterms::all(expr_ref(p, m)), [&](expr* t) { return m_unitary.is_flex(0, t); });
|
||||
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)
|
||||
return { q, p };
|
||||
ptr_vector<expr> todo;
|
||||
vector<std::pair<expr*, unsigned>> todo;
|
||||
ptr_buffer<var> bound;
|
||||
expr_ref_vector cache(m);
|
||||
unsigned nb = q->get_num_decls();
|
||||
todo.push_back(p);
|
||||
bool contains_pat2abs = m_pat2abs.contains(p);
|
||||
SASSERT(m.is_pattern(p));
|
||||
todo.push_back({p, 0});
|
||||
while (!todo.empty()) {
|
||||
auto t = todo.back();
|
||||
auto [t, lvl] = todo.back();
|
||||
if (is_var(t)) {
|
||||
cache.setx(t->get_id(), t);
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (m_unitary.is_flex(0, t)) {
|
||||
m_pat2abs.insert_if_not_there(p, svector<std::pair<unsigned, expr*>>()).push_back({ nb, t });
|
||||
if ((m_unitary.is_flex(0, t) && lvl > 1) || // m.is_lambda_def(t) ||
|
||||
is_lambda(t)) {
|
||||
if (!contains_pat2abs)
|
||||
m_pat2abs.insert_if_not_there(p, svector<std::pair<unsigned, expr*>>()).push_back({ nb, t });
|
||||
auto v = m.mk_var(nb++, t->get_sort());
|
||||
bound.push_back(v);
|
||||
cache.setx(t->get_id(), v);
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (is_app(t)) {
|
||||
auto a = to_app(t);
|
||||
|
||||
unsigned sz = a->get_num_args();
|
||||
ptr_buffer<expr> args;
|
||||
for (auto arg : *a) {
|
||||
cache.reserve(arg->get_id() + 1);
|
||||
expr* arg1 = cache.get(arg->get_id());
|
||||
if (!arg1)
|
||||
todo.push_back(arg);
|
||||
todo.push_back({arg, lvl + 1});
|
||||
else
|
||||
args.push_back(arg1);
|
||||
}
|
||||
|
|
@ -682,11 +703,15 @@ namespace euf {
|
|||
cache.setx(t->get_id(), m.mk_app(a->get_decl(), args.size(), args.data()));
|
||||
}
|
||||
if (is_quantifier(t)) {
|
||||
m_pat2abs.remove(p);
|
||||
if (!contains_pat2abs)
|
||||
m_pat2abs.remove(p);
|
||||
return { q, p };
|
||||
}
|
||||
}
|
||||
p1 = to_app(cache.get(p->get_id()));
|
||||
|
||||
if (p1 == p)
|
||||
return {q, p};
|
||||
expr_free_vars free_vars;
|
||||
free_vars(p1);
|
||||
app_ref_vector new_ground(m);
|
||||
|
|
@ -713,6 +738,8 @@ namespace euf {
|
|||
auto body = q->get_expr();
|
||||
if (!new_patterns.empty()) {
|
||||
ptr_vector<app> pats;
|
||||
CTRACE(ho_matching, !m.is_pattern(p1),
|
||||
tout << mk_pp(p, m) << "\n" << mk_pp(p1, m) << "\n";);
|
||||
VERIFY(m.is_pattern(p1, pats));
|
||||
for (auto p : new_patterns) // patterns for variables that are not free in new pattern
|
||||
pats.push_back(p);
|
||||
|
|
@ -721,23 +748,40 @@ namespace euf {
|
|||
p1 = m.mk_pattern(pats.size(), pats.data());
|
||||
}
|
||||
|
||||
quantifier* q1 = m.mk_forall(sorts.size(), sorts.data(), names.data(), body);
|
||||
q1 = m.mk_forall(sorts.size(), sorts.data(), names.data(), body);
|
||||
|
||||
m_pat2hopat.insert(p, p1);
|
||||
m_hopat2pat.insert(p1, p);
|
||||
m_q2hoq.insert(q, q1);
|
||||
m_hoq2q.insert(q1, q);
|
||||
m_hopat2free_vars.insert(p1, std::move(free_vars));
|
||||
m_ho_patterns.push_back(p1);
|
||||
m_ho_qs.push_back(q1);
|
||||
trail().push(push_back_vector(m_ho_patterns));
|
||||
trail().push(push_back_vector(m_ho_qs));
|
||||
trail().push(insert_map(m_pat2hopat, p));
|
||||
trail().push(insert_map(m_hopat2pat, p1));
|
||||
trail().push(insert_map(m_pat2abs, p));
|
||||
trail().push(insert_map(m_q2hoq, q));
|
||||
trail().push(insert_map(m_hoq2q, q1));
|
||||
trail().push(insert_map(m_hopat2free_vars, p1));
|
||||
|
||||
if (!m_pat2hopat.contains(p)) {
|
||||
m_pat2hopat.insert(p, p1);
|
||||
trail().push(insert_map(m_pat2hopat, p));
|
||||
}
|
||||
if (!m_hopat2pat.contains(p1)) {
|
||||
m_hopat2pat.insert(p1, p);
|
||||
trail().push(insert_map(m_hopat2pat, p1));
|
||||
}
|
||||
if (!m_q2hoq.contains(q)) {
|
||||
m_q2hoq.insert(q, q1);
|
||||
trail().push(insert_map(m_q2hoq, q));
|
||||
}
|
||||
if (!m_hoq2q.contains(q1)) {
|
||||
m_hoq2q.insert(q1, q);
|
||||
trail().push(insert_map(m_hoq2q, q1));
|
||||
}
|
||||
if (!m_hopat2free_vars.contains(p1)) {
|
||||
m_hopat2free_vars.insert(p1, std::move(free_vars));
|
||||
trail().push(insert_map(m_hopat2free_vars, p1));
|
||||
}
|
||||
if (!contains_pat2abs)
|
||||
trail().push(insert_map(m_pat2abs, p));
|
||||
|
||||
TRACE(ho_matching, tout << mk_pp(q, m) << "\n"
|
||||
<< mk_pp(p, m) << "\n->\n"
|
||||
<< mk_pp(q1, m) << "\n"
|
||||
<< mk_pp(p1, m) << "\n");
|
||||
return { q1, p1 };
|
||||
}
|
||||
|
||||
|
|
@ -745,28 +789,46 @@ namespace euf {
|
|||
return m_hopat2pat.contains(p);
|
||||
}
|
||||
|
||||
void ho_matcher::register_ho_pattern(app* alias_p, app* full_p) {
|
||||
if (alias_p == full_p) return;
|
||||
auto orig_p = m_hopat2pat[full_p];
|
||||
m_hopat2pat.insert(alias_p, orig_p);
|
||||
m_hopat2free_vars.insert(alias_p, m_hopat2free_vars[full_p]);
|
||||
m_ho_patterns.push_back(alias_p);
|
||||
trail().push(push_back_vector(m_ho_patterns));
|
||||
trail().push(insert_map(m_hopat2pat, alias_p));
|
||||
trail().push(insert_map(m_hopat2free_vars, alias_p));
|
||||
}
|
||||
|
||||
void ho_matcher::refine_ho_match(app* p, expr_ref_vector& s) {
|
||||
auto fo_pat = m_hopat2pat[p];
|
||||
IF_VERBOSE(10, verbose_stream() << "refine_ho_match: p=" << mk_pp(p, m) << "\n fo_pat=" << mk_pp(fo_pat, m) << "\n";
|
||||
verbose_stream() << " m_pat2abs has fo_pat: " << m_pat2abs.contains(fo_pat) << "\n";
|
||||
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";);
|
||||
m_trail.push_scope();
|
||||
m_subst.resize(0);
|
||||
m_subst.resize(s.size());
|
||||
m_goals.reset();
|
||||
// MAM bindings are reversed: s[i] = binding for var idx = s.size()-1-i
|
||||
// m_subst is indexed by var index directly
|
||||
for (unsigned i = 0; i < s.size(); ++i) {
|
||||
auto idx = s.size() - i - 1;
|
||||
if (!m_hopat2free_vars[p].contains(idx))
|
||||
s[i] = m.mk_var(idx, s[i]->get_sort());
|
||||
else if (s.get(i))
|
||||
m_subst.set(i, s.get(i));
|
||||
m_subst.set(idx, s.get(i));
|
||||
}
|
||||
|
||||
IF_VERBOSE(1, verbose_stream() << "refine " << mk_pp(p, m) << "\n" << s << "\n");
|
||||
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]) {
|
||||
var_subst sub(m, true);
|
||||
auto pat_refined = sub(pat, s);
|
||||
IF_VERBOSE(1, verbose_stream() << mk_pp(pat, m) << " -> " << pat_refined << "\n");
|
||||
m_goals.push(level, num_bound, pat_refined, s.get(s.size() - v - 1));
|
||||
TRACE(ho_matching, tout << mk_pp(pat, m) << " -> " << pat_refined << "\n");
|
||||
m_goals.push(level, num_bound, pat_refined, m_subst.get(v));
|
||||
}
|
||||
|
||||
search();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ Author:
|
|||
#include "ast/for_each_expr.h"
|
||||
#include "ast/reg_decl_plugins.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/rewriter/array_rewriter.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
|
||||
|
|
@ -88,13 +89,15 @@ namespace euf {
|
|||
}
|
||||
|
||||
match_goal(unsigned level, unsigned offset, expr_ref const& pat, expr_ref const& t) noexcept :
|
||||
base_offset(offset), pat(pat), t(t), level(level) {}
|
||||
base_offset(offset), pat(pat), t(t), level(level) {
|
||||
SASSERT(pat->get_sort() == t->get_sort());
|
||||
}
|
||||
|
||||
unsigned term_offset() const { return base_offset + delta_offset; }
|
||||
unsigned pat_offset() const { return base_offset + delta_offset; }
|
||||
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
return out << "[" << level << ":" << base_offset + delta_offset << "] " << pat << " ~ " << t << "\n";
|
||||
return out << "[" << level << ":" << base_offset + delta_offset << "] " << mk_bounded_pp(pat, pat.m()) << " ~ " << mk_bounded_pp(t, t.m()) << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -329,6 +332,8 @@ namespace euf {
|
|||
bool consume_work(match_goal& wi);
|
||||
|
||||
expr_ref whnf(expr* e, unsigned offset) const;
|
||||
|
||||
expr_ref whnf_star(expr *e, unsigned offset) const;
|
||||
|
||||
bool is_bound_var(expr* v, unsigned offset) const { return is_var(v) && to_var(v)->get_idx() < offset; }
|
||||
|
||||
|
|
@ -389,11 +394,23 @@ namespace euf {
|
|||
|
||||
bool is_ho_pattern(app* p);
|
||||
|
||||
// Register an alias pattern (e.g., after stripping ground elements)
|
||||
// that maps to the same original pattern as full_p
|
||||
void register_ho_pattern(app* alias_p, app* full_p);
|
||||
|
||||
void refine_ho_match(app* p, expr_ref_vector& s);
|
||||
|
||||
bool is_free(app* p, unsigned i) const { return m_hopat2free_vars[p].contains(i); }
|
||||
|
||||
quantifier* hoq2q(quantifier* q) const { return m_hoq2q[q]; }
|
||||
|
||||
|
||||
svector<std::pair<unsigned, expr*>> const* get_flex_subterms(app* p) const {
|
||||
auto orig_p = m_hopat2pat.find_core(p);
|
||||
if (!orig_p) return nullptr;
|
||||
auto abs = m_pat2abs.find_core(orig_p->get_data().get_value());
|
||||
return abs ? &abs->get_data().get_value() : nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2976,13 +2976,12 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar
|
|||
prev_bit = bit;
|
||||
}
|
||||
|
||||
expr_ref one_div_exp2(m);
|
||||
one_div_exp2 = m_arith_util.mk_div(one, exp2);
|
||||
exp2 = m.mk_ite(exp_is_neg, one_div_exp2, exp2);
|
||||
dbg_decouple("fpa2bv_to_real_exp2", exp2);
|
||||
|
||||
expr_ref res(m), two_exp2(m), minus_res(m), sgn_is_1(m);
|
||||
expr_ref two_exp2(m), one_div_two_exp2(m);
|
||||
two_exp2 = m_arith_util.mk_power(two, exp2);
|
||||
one_div_two_exp2 = m_arith_util.mk_div(one, two_exp2);
|
||||
two_exp2 = m.mk_ite(exp_is_neg, one_div_two_exp2, two_exp2);
|
||||
dbg_decouple("fpa2bv_to_real_exp2", two_exp2);
|
||||
expr_ref res(m), minus_res(m), sgn_is_1(m);
|
||||
res = m_arith_util.mk_mul(rsig, two_exp2);
|
||||
minus_res = m_arith_util.mk_uminus(res);
|
||||
sgn_is_1 = m.mk_eq(sgn, bv1);
|
||||
|
|
@ -2990,7 +2989,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar
|
|||
dbg_decouple("fpa2bv_to_real_sig_times_exp2", res);
|
||||
|
||||
TRACE(fpa2bv_to_real, tout << "rsig = " << mk_ismt2_pp(rsig, m) << std::endl;
|
||||
tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;);
|
||||
tout << "two_exp2 = " << mk_ismt2_pp(two_exp2, m) << std::endl;);
|
||||
|
||||
expr_ref unspec(m);
|
||||
mk_to_real_unspecified(f, num, args, unspec);
|
||||
|
|
|
|||
|
|
@ -121,9 +121,6 @@ app * defined_names::impl::gen_name(expr * e, sort_ref_buffer & var_sorts, buffe
|
|||
sort * range = e->get_sort();
|
||||
func_decl * new_skolem_decl = m.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.data(), range);
|
||||
app * n = m.mk_app(new_skolem_decl, new_args.size(), new_args.data());
|
||||
if (is_lambda(e)) {
|
||||
m.add_lambda_def(new_skolem_decl, to_quantifier(e));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
@ -193,43 +190,7 @@ void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var
|
|||
else if (m.is_term_ite(e)) {
|
||||
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(to_app(e)->get_arg(0)), MK_EQ(n, to_app(e)->get_arg(1))), n, defs);
|
||||
bound_vars(var_sorts, var_names, MK_OR(to_app(e)->get_arg(0), MK_EQ(n, to_app(e)->get_arg(2))), n, defs);
|
||||
}
|
||||
else if (is_lambda(e)) {
|
||||
// n(y) = \x . M[x,y]
|
||||
// =>
|
||||
// n(y)[x] = M, forall x y
|
||||
//
|
||||
// NB. The pattern is incomplete.
|
||||
// consider store(a, i, v) == \lambda j . if i = j then v else a[j]
|
||||
// the instantiation rules for store(a, i, v) are:
|
||||
// store(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] }
|
||||
// The first pattern is not included.
|
||||
// TBD use a model-based scheme for extracting instantiations instead of
|
||||
// using multi-patterns.
|
||||
//
|
||||
|
||||
quantifier* q = to_quantifier(e);
|
||||
expr_ref_vector args(m);
|
||||
expr_ref n2(m), n3(m);
|
||||
var_shifter vs(m);
|
||||
vs(n, q->get_num_decls(), n2);
|
||||
args.push_back(n2);
|
||||
var_sorts.append(q->get_num_decls(), q->get_decl_sorts());
|
||||
var_names.append(q->get_num_decls(), q->get_decl_names());
|
||||
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
|
||||
args.push_back(m.mk_var(q->get_num_decls() - i - 1, q->get_decl_sort(i)));
|
||||
}
|
||||
array_util autil(m);
|
||||
func_decl * f = nullptr;
|
||||
if (autil.is_as_array(n2, f)) {
|
||||
n3 = m.mk_app(f, args.size()-1, args.data() + 1);
|
||||
}
|
||||
else {
|
||||
n3 = autil.mk_select(args.size(), args.data());
|
||||
}
|
||||
bound_vars(var_sorts, var_names, MK_EQ(q->get_expr(), n3), to_app(n3), defs, m.lambda_def_qid());
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
bound_vars(var_sorts, var_names, MK_EQ(e, n), n, defs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ class name_quantifier_labels : public name_exprs_core {
|
|||
public:
|
||||
pred(ast_manager & m):m(m) {}
|
||||
bool operator()(expr * t) override {
|
||||
return is_quantifier(t) || m.is_label(t);
|
||||
return (is_quantifier(t) && !is_lambda(t)) || m.is_label(t);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ class name_nested_formulas : public name_exprs_core {
|
|||
TRACE(name_exprs, tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m) << "\n";);
|
||||
if (is_app(t))
|
||||
return to_app(t)->get_family_id() == m.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
|
||||
return m.is_label(t) || is_quantifier(t);
|
||||
return m.is_label(t) || (is_quantifier(t) && !is_lambda(t));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ struct pull_quant::imp {
|
|||
var_names.data(),
|
||||
nested_q->get_expr(),
|
||||
std::min(q->get_weight(), nested_q->get_weight()),
|
||||
m.is_lambda_def(q) ? symbol("pulled-lambda") : q->get_qid());
|
||||
q->get_qid());
|
||||
}
|
||||
|
||||
void pull_quant1(quantifier * q, expr * new_expr, expr_ref & result) {
|
||||
|
|
|
|||
|
|
@ -254,6 +254,27 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
case AST_QUANTIFIER: {
|
||||
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) {
|
||||
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();
|
||||
quantifier_ref new_q(m);
|
||||
if (new_body != q->get_expr())
|
||||
new_q = m.update_quantifier(q, new_body);
|
||||
else
|
||||
new_q = q;
|
||||
save(n, delta, alloc(info, m, new_q, body_info->m_free_vars, body_info->m_size + 1));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
save(n, delta, nullptr);
|
||||
return;
|
||||
|
|
@ -363,6 +384,8 @@ bool pattern_inference_cfg::contains_subpattern::operator()(expr * n) {
|
|||
break;
|
||||
case AST_VAR:
|
||||
break;
|
||||
case AST_QUANTIFIER:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
@ -525,7 +548,7 @@ void pattern_inference_cfg::reset_pre_patterns() {
|
|||
|
||||
|
||||
bool pattern_inference_cfg::is_forbidden(app * n) const {
|
||||
func_decl const * decl = n->get_decl();
|
||||
func_decl * decl = n->get_decl();
|
||||
if (is_ground(n))
|
||||
return false;
|
||||
// Remark: skolem constants should not be used in patterns, since they do not
|
||||
|
|
|
|||
|
|
@ -444,7 +444,8 @@ namespace recfun {
|
|||
|
||||
promise_def plugin::mk_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated) {
|
||||
def* d = u().decl_fun(name, n, params, range, is_generated);
|
||||
SASSERT(!m_defs.contains(d->get_decl()));
|
||||
if (m_defs.contains(d->get_decl()))
|
||||
throw default_exception(std::string("recursive function ") + name.str() + " already defined");
|
||||
m_defs.insert(d->get_decl(), d);
|
||||
return promise_def(&u(), d);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -750,7 +750,10 @@ bool array_rewriter::add_store(expr_ref_vector& args, unsigned num_idxs, expr* e
|
|||
}
|
||||
if (is_var(e1) && is_ground(e2)) {
|
||||
unsigned idx = to_var(e1)->get_idx();
|
||||
args[num_idxs - idx - 1] = e2;
|
||||
unsigned nidx = num_idxs - idx - 1;
|
||||
if (args.get(nidx) && args.get(nidx) != e2)
|
||||
return false;
|
||||
args[nidx] = e2;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
|
@ -858,19 +861,45 @@ br_status array_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result)
|
|||
return false;
|
||||
};
|
||||
|
||||
auto domain_is_larger_than = [&](sort* s, unsigned num_stores) {
|
||||
unsigned sz = get_array_arity(s);
|
||||
rational dsz(1);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
sort* d = get_array_domain(s, i);
|
||||
if (d->is_infinite())
|
||||
return true;
|
||||
if (d->is_very_big())
|
||||
return false;
|
||||
dsz *= rational(d->get_num_elements().size(), rational::ui64());
|
||||
if (dsz > rational(num_stores, rational::ui64()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
expr* lhs1 = lhs;
|
||||
expr* rhs1 = rhs;
|
||||
unsigned num_lhs = 0, num_rhs = 0;
|
||||
while (m_util.is_store(lhs1)) {
|
||||
lhs1 = to_app(lhs1)->get_arg(0);
|
||||
++num_lhs;
|
||||
}
|
||||
while (m_util.is_store(rhs1)) {
|
||||
rhs1 = to_app(rhs1)->get_arg(0);
|
||||
++num_rhs;
|
||||
}
|
||||
|
||||
if (m_util.is_const(lhs1, v) && m_util.is_const(rhs1, w) &&
|
||||
domain_is_larger_than(lhs->get_sort(), num_lhs + num_rhs)) {
|
||||
mk_eq(lhs, lhs, rhs, fmls);
|
||||
mk_eq(rhs, lhs, rhs, fmls);
|
||||
fmls.push_back(m().mk_eq(v, w));
|
||||
result = m().mk_and(fmls);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
|
||||
if (m_expand_store_eq) {
|
||||
expr* lhs1 = lhs;
|
||||
expr* rhs1 = rhs;
|
||||
unsigned num_lhs = 0, num_rhs = 0;
|
||||
while (m_util.is_store(lhs1)) {
|
||||
lhs1 = to_app(lhs1)->get_arg(0);
|
||||
++num_lhs;
|
||||
}
|
||||
while (m_util.is_store(rhs1)) {
|
||||
rhs1 = to_app(rhs1)->get_arg(0);
|
||||
++num_rhs;
|
||||
}
|
||||
if (lhs1 == rhs1) {
|
||||
mk_eq(lhs, lhs, rhs, fmls);
|
||||
mk_eq(rhs, lhs, rhs, fmls);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ struct enum2bv_rewriter::imp {
|
|||
new_body_ref = mk_and(bounds);
|
||||
break;
|
||||
case lambda_k:
|
||||
case choice_k:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue