Rust SAT求解器库varisat-dimacs的使用,支持DIMACS格式的CNF公式解析与求解

Varisat - DIMACS

DIMACS CNF解析器和写入器,用于Varisat SAT求解器。

此crate的功能由主Varisat crate重新导出。

许可证

Varisat源代码根据以下任一许可证授权:

  • Apache License, Version 2.0
  • MIT license

根据您的选择。

贡献

除非您明确声明,否则任何有意提交给Varisat的贡献,如Apache-2.0许可证中所定义,应按照上述双重许可,没有任何附加条款或条件。

元数据

pkg:cargo/varisat-dimacs@0.2.2

大约5年前

2018版本

MIT OR Apache-2.0

9.65 KiB

安装

在您的项目目录中运行以下Cargo命令:

cargo add varisat-dimacs

或在您的Cargo.toml中添加以下行:

varisat-dimacs = “0.2.2”

主页

文档

仓库

所有者

Jannis Harder

完整示例demo:

use varisat_dimacs::{DimacsParser, DimacsWriter};
use std::io::{Cursor, Read, Write};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // DIMACS CNF格式示例
    let cnf_input = r"
        p cnf 3 2
        1 -2 3 0
        -1 2 0
    ";
    
    // 解析DIMACS CNF公式
    let mut parser = DimacsParser::new(Cursor::new(cnf_input));
    let cnf_formula = parser.parse()?;
    
    println!("解析的CNF公式: {:?}", cnf_formula);
    
    // 将CNF公式写回DIMACS格式
    let mut output = Vec::new();
    let mut writer = DimacsWriter::new(&mut output);
    writer.write_cnf(&cnf_formula)?;
    
    let output_str = String::from_utf8(output)?;
    println!("生成的DIMACS输出:\n{}", output_str);
    
    Ok(())
}
use varisat::{solver::Solver, dimacs::DimacsParser};
use std::io::Cursor;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建SAT求解器
    let mut solver = Solver::new();
    
    // DIMACS CNF公式
    let cnf_input = r"
        p cnf 3 3
        1 2 3 0
        -1 -2 0
        -2 -3 0
    ";
    
    // 解析并添加公式到求解器
    let mut parser = DimacsParser::new(Cursor::new(cnf_input));
    solver.add_formula(&parser.parse()?);
    
    // 求解SAT问题
    match solver.solve() {
        Ok(true) => {
            println!("公式可满足");
            if let Some(model) = solver.model() {
                println!("满足赋值: {:?}", model);
            }
        }
        Ok(false) => {
            println!("公式不可满足");
        }
        Err(e) => {
            eprintln!("求解错误: {}", e);
        }
    }
    
    Ok(())
}
use varisat_dimacs::DimacsParser;
use std::fs::File;
use std::io::BufReader;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 从文件读取DIMACS CNF
    let file = File::open("example.cnf")?;
    let reader = BufReader::new(file);
    
    let mut parser = DimacsParser::new(reader);
    let cnf_formula = parser.parse()?;
    
    println!("变量数量: {}", cnf_formula.var_count());
    println!("子句数量: {}", cnf_formula.len());
    
    // 处理每个子句
    for (i, clause) in cnf_formula.iter().enumerate() {
        println!("子句 {}: {:?}", i + 1, clause);
    }
    
    Ok(())
}

1 回复

Rust SAT求解器库:varisat-dimacs 使用指南

概述

varisat-dimacs 是一个基于 Rust 的 SAT 求解器库,专门用于解析和求解 DIMACS 格式的 CNF(合取范式)公式。该库提供了高效的解析器和求解器实现,适用于需要布尔可满足性求解的应用场景。

核心功能

  • DIMACS CNF 格式解析
  • 高效的 SAT 求解算法
  • 可配置的求解选项
  • 结果验证与模型输出

安装方法

在 Cargo.toml 中添加依赖:

[dependencies]
varisat-dimacs = "0.3"

基本用法

1. 解析 DIMACS CNF 文件

use varisat_dimacs::DimacsParser;
use std::fs::File;
use std::io::BufReader;

fn parse_cnf_file() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::open("example.cnf")?;
    let reader = BufReader::new(file);
    
    let cnf = DimacsParser::parse(reader)?;
    println!("解析成功,包含 {} 个子句", cnf.num_clauses());
    
    Ok(())
}

2. 求解 CNF 公式

use varisat_dimacs::{DimacsParser, Solver};
use std::io::Cursor;

fn solve_cnf() -> Result<(), Box<dyn std::error::Error>> {
    // 示例 CNF 公式:(x1 ∨ ¬x2) ∧ (x2 ∨ x3)
    let cnf_input = "p cnf 3 2\n1 -2 0\n2 3 0";
    
    let cnf = DimacsParser::parse(Cursor::new(cnf_input))?;
    let mut solver = Solver::new();
    
    // 添加所有子句到求解器
    for clause in cnf.clauses() {
        solver.add_clause(clause.iter().copied());
    }
    
    // 求解
    match solver.solve() {
        Some(true) => {
            println!("公式可满足");
            if let Some(model) = solver.model() {
                println!("解模型: {:?}", model);
            }
        }
        Some(false) => println!("公式不可满足"),
        None => println!("求解超时"),
    }
    
    Ok(())
}

3. 从字符串解析并求解

use varisat_dimacs::{DimacsParser, Solver};

fn solve_from_string() {
    let cnf_content = r#"
        p cnf 4 3
        1 -2 3 0
        -1 2 4 0
        -3 -4 0
    "#;
    
    let cnf = DimacsParser::parse(cnf_content.as_bytes()).unwrap();
    let mut solver = Solver::new();
    
    solver.add_formula(&cnf);
    
    if let Some(true) = solver.solve() {
        println!("找到解: {:?}", solver.model().unwrap());
    }
}

高级配置

设置求解器选项

use varisat_dimacs::Solver;
use varisat::config::SolverConfig;

fn configure_solver() {
    let config = SolverConfig::default()
        .time_limit(std::time::Duration::from_secs(10))
        .conflict_budget(1000);
    
    let mut solver = Solver::with_config(config);
    // ... 添加公式并求解
}

错误处理

use varisat_dimacs::DimacsParser;
use std::io::ErrorKind;

fn handle_parsing_errors() -> Result<(), Box<dyn std::error::Error>> {
    let invalid_cnf = "invalid cnf content";
    
    match DimacsParser::parse(invalid_cnf.as_bytes()) {
        Ok(cnf) => {
            // 处理成功解析
            println!("成功解析 CNF");
        }
        Err(e) => {
            eprintln!("解析错误: {}", e);
            // 处理特定错误类型
        }
    }
    
    Ok(())
}

性能提示

  • 对于大型 CNF 文件,建议使用文件流式解析
  • 可以调整求解器配置以获得更好的性能
  • 考虑使用增量求解模式处理相关公式序列

示例 CNF 格式

p cnf 3 2
1 -2 0
2 3 0

其中:

  • p cnf 表示 CNF 问题格式
  • 3 表示变量数量
  • 2 表示子句数量
  • 每行以 0 结束表示一个子句
  • 数字表示变量(负号表示否定)

这个库为处理 SAT 问题提供了完整的解决方案,从解析到求解都包含在内。

完整示例代码

// 完整示例:演示 varisat-dimacs 库的完整使用流程
use varisat_dimacs::{DimacsParser, Solver};
use varisat::config::SolverConfig;
use std::fs::File;
use std::io::{BufReader, Cursor, Write};
use std::time::Duration;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 示例1:从文件解析 CNF
    println!("=== 示例1:从文件解析 CNF ===");
    if let Ok(file) = File::open("example.cnf") {
        let reader = BufReader::new(file);
        match DimacsParser::parse(reader) {
            Ok(cnf) => {
                println!("成功解析文件,包含 {} 个子句", cnf.num_clauses());
            }
            Err(e) => {
                eprintln!("文件解析错误: {}", e);
            }
        }
    } else {
        println!("未找到 example.cnf 文件,跳过文件解析示例");
    }

    // 示例2:从字符串解析并求解
    println!("\n=== 示例2:从字符串解析并求解 ===");
    let cnf_content = r#"
        p cnf 4 3
        1 -2 3 0
        -1 2 4 0
        -3 -4 0
    "#;
    
    let cnf = DimacsParser::parse(cnf_content.as_bytes())?;
    let mut solver = Solver::new();
    solver.add_formula(&cnf);
    
    match solver.solve() {
        Some(true) => {
            println!("公式可满足");
            if let Some(model) = solver.model() {
                println!("解模型: {:?}", model);
            }
        }
        Some(false) => println!("公式不可满足"),
        None => println!("求解超时"),
    }

    // 示例3:使用配置的求解器
    println!("\n=== 示例3:使用配置的求解器 ===");
    let config = SolverConfig::default()
        .time_limit(Duration::from_secs(5))
        .conflict_budget(5000);
    
    let mut configured_solver = Solver::with_config(config);
    
    // 创建另一个测试公式
    let test_formula = "p cnf 3 2\n1 -2 0\n2 3 0";
    let test_cnf = DimacsParser::parse(Cursor::new(test_formula))?;
    configured_solver.add_formula(&test_cnf);
    
    match configured_solver.solve() {
        Some(true) => println!("配置求解器:公式可满足"),
        Some(false) => println!("配置求解器:公式不可满足"),
        None => println!("配置求解器:求解超时"),
    }

    // 示例4:错误处理演示
    println!("\n=== 示例4:错误处理演示 ===");
    let invalid_cnf = "invalid cnf content";
    match DimacsParser::parse(invalid_cnf.as_bytes()) {
        Ok(_) => println!("意外成功解析"),
        Err(e) => println!("正确捕获解析错误: {}", e),
    }

    Ok(())
}

// 辅助函数:创建示例 CNF 文件
fn create_example_cnf() -> Result<(), Box<dyn std::error::Error>> {
    let mut file = File::create("example.cnf")?;
    file.write_all(b"p cnf 3 2\n1 -2 0\n2 3 0")?;
    println!("已创建示例 CNF 文件: example.cnf");
    Ok(())
}

// 运行前可调用此函数创建测试文件
// create_example_cnf().unwrap();

这个完整示例演示了 varisat-dimacs 库的主要功能:

  1. 从文件解析 CNF 公式
  2. 从字符串内容解析并求解
  3. 使用自定义配置的求解器
  4. 错误处理的最佳实践
  5. 包含创建测试文件的辅助函数

要运行此示例,请确保在 Cargo.toml 中添加了正确的依赖,并根据需要创建测试文件。

回到顶部