Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

testcases in concrete_driver examples includes check phase for linearity check coverage #141

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b82e368
Statement::Return checks all Serial types are consumed in each function
kenarab May 31, 2024
4c14cde
Coding for testcases to use options
kenarab May 31, 2024
e3a226a
cargo clippy & cargo fmt
kenarab May 31, 2024
2947d37
codecov.yml intended for not triggering when coverage is not increased
kenarab May 31, 2024
b15c413
Merge branch 'ast-refactor' into linear-checker-dev
kenarab Jun 3, 2024
ecc42b2
[refactor] for running examples with args
kenarab Jun 3, 2024
077984c
Merged with PR #127
kenarab Jun 3, 2024
a0d5d4f
compile_program calls compile_program_with_args
kenarab Jun 3, 2024
3991dfa
Removed commented code and debug info
kenarab Jun 3, 2024
ac7b64e
tests can be run with check but are failing so disconnected them
kenarab Jun 3, 2024
532f6fd
Merge branch 'main' into linear-checker-dev
kenarab Jun 3, 2024
887044d
Merge branch 'ast-refactor' into linear-checker-dev
kenarab Jun 3, 2024
9ce736c
Linearity tests almost working
kenarab Jun 5, 2024
1798e9e
Merge branch 'ast-refactor' into linear-checker-dev
kenarab Jun 5, 2024
8cde355
tests for linearity checks are working
kenarab Jun 5, 2024
a564e68
cargo clippy & cargo fmt
kenarab Jun 5, 2024
0f9a907
cargo clippy by CI
kenarab Jun 5, 2024
b150a05
cargo clippy by CI
kenarab Jun 5, 2024
736237d
Identation in tests/examples.rs
kenarab Jun 7, 2024
41f620d
Removed unwrap in concrete_check
kenarab Jun 7, 2024
413456b
Merge remote-tracking branch 'origin/main' into linear-checker-dev
kenarab Jun 7, 2024
9e9804e
Merge branch 'main' into linear-checker-dev
igaray Jun 7, 2024
d4a9c2c
Merge remote-tracking branch 'origin/main' into linear-checker-dev
kenarab Jun 7, 2024
16fd6e7
Merge remote-tracking branch 'origin/linear-checker-dev' into linear-…
kenarab Jun 7, 2024
5bc16e4
make check
kenarab Jun 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
codecov:
require_ci_to_pass: yes

coverage:
status:
project:
default:
target: auto # Automatically sets the target based on the previous commits
threshold: 0% # Allows any decrease in coverage without failing the check
base: auto
patch:
default:
target: auto # Automatically sets the target based on the previous commits
threshold: 0% # Allows any decrease in coverage without failing the check
base: auto
44 changes: 22 additions & 22 deletions crates/concrete_check/src/linearity_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,15 +268,13 @@ impl LinearityChecker {
context: &str,
) -> Result<StateTbl, LinearityError> {
// Assuming you have a method to get all variable names and types
//let vars = &mut self.state_tbl.vars;
//TODO check if we can avoid cloning
let vars = state_tbl.vars.clone();
println!("Check_expr vars {:?}", vars);
for (name, _info) in vars.iter() {
//self.check_var_in_expr(depth, &name, &info.ty, expr)?;
state_tbl = self
.check_var_in_expr(state_tbl, depth, name, expr, context)
.unwrap();
.expect("Linearity error");
}
Ok(state_tbl)
}
Expand Down Expand Up @@ -662,6 +660,7 @@ impl LinearityChecker {
stmt: &Statement,
context: &str,
) -> Result<StateTbl, LinearityError> {
let mut errors: Vec<LinearityError> = Vec::new();
match stmt {
Statement::Let(binding) => {
// Handle let bindings, possibly involving pattern matching
Expand Down Expand Up @@ -721,28 +720,25 @@ impl LinearityChecker {
Ok(state_tbl)
}
Statement::Return(return_stmt) => {
let errors: Vec<LinearityError> = Vec::new();
if let Some(return_stmt) = &return_stmt.value {
state_tbl = self.check_expr(state_tbl, depth, return_stmt, "return")?;
}
// Ensure that all variables are properly consumed
for (name, var_info) in state_tbl.vars.iter() {
//FIXME implement Checking of consumed variables
/*
match var_info.state {
VarState::Consumed => (), // If consumed, do nothing.
VarState::Consumed => (), // If consumed, no action needed
_ => match var_info.ty {
Type::WriteRef(_) | Type::SpanMut(_) => (), // Write references and write spans can be dropped implicitly.
_ if self.universe_linear_ish(var_info.ty) => {
// If the type is linear-ish and the variable is not consumed, raise an error.
errors.push(Err(LinearityError::VariableNotConsumed {
variable_name: name.clone(),
message: format!("The variable {} is not consumed by the time of the return statement. Did you forget to call a destructor, or destructure the contents?", name),
}));
()
// Type::WriteRef(_) | Type::SpanMut(_) => (), // These can be dropped implicitly
_ if self.is_universe_linear_ish(&var_info.ty) => {
// Collect error if a variable that needs to be consumed hasn't been
errors.push(LinearityError::VariableNotConsumed {
variable: name.clone(),
});
}
_ => ()
}
_ => (),
},
}
*/
}
//if errors.len() > 0 {
if !errors.is_empty() {
Err(errors[0].clone())
} else {
Expand Down Expand Up @@ -784,6 +780,10 @@ impl LinearityChecker {
)
}

fn is_universe_linear_ish(&self, ty: &str) -> bool {
*ty == *"Linear".to_string()
}

fn check_var_in_expr(
&self,
state_tbl: StateTbl,
Expand All @@ -796,7 +796,7 @@ impl LinearityChecker {
if let Some(info) = info {
//Only checks Linearity for types of name Linear
// TODO improve this approach
if info.ty == *"Linear".to_string() {
if self.is_universe_linear_ish(&info.ty) {
let state = &info.state;
let apps = self.count_in_expression(name, expr); // Assume count function implementation
let Appearances {
Expand Down Expand Up @@ -921,7 +921,7 @@ impl LinearityChecker {
pub fn linearity_check_program(
programs: &Vec<(PathBuf, String, Program)>,
_session: &Session,
) -> Result<String, LinearityError> {
) -> Result<(), LinearityError> {
tracing::debug!("Starting linearity check");
let checker = LinearityChecker::new();
for (_path, name, program) in programs {
Expand Down Expand Up @@ -990,5 +990,5 @@ pub fn linearity_check_program(
}
}
}
Ok("OK".to_string())
Ok(())
}
4 changes: 3 additions & 1 deletion crates/concrete_check/src/linearity_check/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use thiserror::Error;

#[derive(Debug, Error, Clone)]
#[derive(Debug, Error, Clone, PartialEq)]
pub enum LinearityError {
#[error("Variable {variable} not consumed")]
NotConsumed { variable: String },
Expand All @@ -24,6 +24,8 @@ pub enum LinearityError {
UnhandledStateOrCount { variable: String },
#[error("Consumed variable {variable} in loop created outside the loop")]
ConsumedVariableInLoop { variable: String },
#[error("Variable {variable} not consumed")]
VariableNotConsumed { variable: String },
#[error("Unspecified Linearity error. Variable {variable} generated {message}")]
Unspecified { variable: String, message: String },
#[error("Variable {variable} not found")]
Expand Down
40 changes: 20 additions & 20 deletions crates/concrete_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use concrete_session::{
Session,
};
use config::{Package, Profile};
use core::panic;
use db::Database;
use git2::{IndexAddOption, Repository};
use owo_colors::OwoColorize;
Expand Down Expand Up @@ -110,54 +111,54 @@ pub struct BuildArgs {
#[command(author, version, about = "concrete compiler", long_about = None)]
pub struct CompilerArgs {
/// The input file.
input: PathBuf,
pub input: PathBuf,

/// The output file.
pub output: PathBuf,

/// Build for release with all optimizations.
#[arg(short, long, default_value_t = false)]
release: bool,
pub release: bool,

/// Set the optimization level, 0,1,2,3
#[arg(short = 'O', long)]
optlevel: Option<u8>,
pub optlevel: Option<u8>,

/// Always add debug info
#[arg(long)]
pub debug_info: Option<bool>,

/// Build as a library.
#[arg(short, long, default_value_t = false)]
library: bool,
pub library: bool,

/// Also output the ast.
#[arg(long, default_value_t = false)]
ast: bool,
pub ast: bool,

/// Also output the ir.
#[arg(long, default_value_t = false)]
ir: bool,
pub ir: bool,

/// Also output the llvm ir file.
#[arg(long, default_value_t = false)]
llvm: bool,
pub llvm: bool,

/// Also output the mlir file
#[arg(long, default_value_t = false)]
mlir: bool,
pub mlir: bool,

/// Also output the asm file.
#[arg(long, default_value_t = false)]
asm: bool,
pub asm: bool,

/// Also output the object file.
#[arg(long, default_value_t = false)]
object: bool,
pub object: bool,

/// This option is for checking the program for linearity.
#[arg(long, default_value_t = false)]
check: bool,
pub check: bool,
}

pub fn main() -> Result<()> {
Expand Down Expand Up @@ -605,15 +606,14 @@ pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {

#[allow(unused_variables)]
if args.check {
let linearity_result =
match concrete_check::linearity_check::linearity_check_program(&programs, &session) {
Ok(ir) => ir,
Err(error) => {
//TODO improve reporting
println!("Linearity check failed: {:#?}", error);
std::process::exit(1);
}
};
//let linearity_result =
match concrete_check::linearity_check::linearity_check_program(&programs, &session) {
Ok(ir) => ir,
Err(error) => {
//TODO improve reporting
panic!("Linearity check failed: {:#?}", error);
}
};
}

if args.ir {
Expand Down
108 changes: 99 additions & 9 deletions crates/concrete_driver/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use std::{
};

use ariadne::Source;
use concrete_ast::Program;
use concrete_driver::linker::{link_binary, link_shared_lib};
use concrete_driver::CompilerArgs;
use concrete_ir::lowering::lower_programs;
use concrete_parser::{error::Diagnostics, ProgramSource};
use concrete_session::{
Expand Down Expand Up @@ -39,7 +41,41 @@ pub fn compile_program(
library: bool,
optlevel: OptLevel,
) -> Result<CompileResult, Box<dyn std::error::Error>> {
let mut input_path = std::env::current_dir()?;
input_path = input_path.join(source);
let build_dir = std::env::current_dir()?;
let output = build_dir.join(source);

let compile_args = CompilerArgs {
input: input_path.clone(),
output: output.clone(),
release: false,
ast: false,
optlevel: None,
debug_info: None,
library,
ir: false,
llvm: false,
mlir: false,
asm: false,
object: false,
check: false,
};
compile_program_with_args(source, name, library, optlevel, &compile_args)
}

pub fn compile_program_with_args(
source: &str,
name: &str,
library: bool,
optlevel: OptLevel,
args: &CompilerArgs,
) -> Result<CompileResult, Box<dyn std::error::Error>> {
let mut programs_for_check: Vec<(PathBuf, String, Program)> = Vec::new();

let db = concrete_driver::db::Database::default();
// Real source for programs_for_check
let real_source = source.to_string();
let source = ProgramSource::new(&db, source.to_string(), name.to_string());
tracing::debug!("source code:\n{}", source.input(&db));
let mut program = match concrete_parser::parse_ast(&db, source) {
Expand All @@ -59,10 +95,15 @@ pub fn compile_program(
let test_dir = tempfile::tempdir()?;
let test_dir_path = test_dir.path();

let input_file = test_dir_path.join(name).with_extension(".con");
let input_file = test_dir_path.join(name).with_extension("con");

//Build Vec for programs_for_check before moving program
if args.check {
programs_for_check.push((input_file.clone(), real_source, program.clone()));
}

std::fs::write(&input_file, source.input(&db))?;
program.file_path = Some(input_file.clone());

let output_file = test_dir_path.join(name);
let output_file = if library {
output_file.with_extension(Session::get_platform_library_ext())
Expand All @@ -84,6 +125,23 @@ pub fn compile_program(
file_paths: vec![input_file],
};

// By now only used check for being able to run tests with linearity checking
let mut linearity_errors = Vec::new();
//#[allow(unused_variables)]
if args.check {
match concrete_check::linearity_check::linearity_check_program(
&programs_for_check,
&session,
) {
Ok(ir) => ir,
Err(error) => {
//TODO improve reporting
println!("Linearity check failed: {:#?}", error);
linearity_errors.push(error);
}
};
}

let program_ir = lower_programs(&[program])?;

let object_path = concrete_codegen_mlir::compile(&session, &program_ir)?;
Expand All @@ -101,12 +159,25 @@ pub fn compile_program(
&session.output_file.with_extension(""),
)?;
}
if !linearity_errors.is_empty() {
let error = build_test_linearity_error(&linearity_errors[0]);
Err(error)
} else {
Ok(CompileResult {
folder: test_dir,
object_file: object_path,
binary_file: session.output_file,
})
}
}

Ok(CompileResult {
folder: test_dir,
object_file: object_path,
binary_file: session.output_file,
})
pub fn build_test_linearity_error(
linearity_error: &concrete_check::linearity_check::errors::LinearityError,
) -> Box<dyn std::error::Error> {
let mut ret = "Linearity check failed<".to_string();
ret.push_str(&linearity_error.to_string());
ret.push('>');
Box::new(TestError(ret.into()))
}

pub fn run_program(program: &Path) -> Result<Output, std::io::Error> {
Expand All @@ -119,12 +190,31 @@ pub fn run_program(program: &Path) -> Result<Output, std::io::Error> {
#[track_caller]
pub fn compile_and_run(source: &str, name: &str, library: bool, optlevel: OptLevel) -> i32 {
let result = compile_program(source, name, library, optlevel).expect("failed to compile");

let output = run_program(&result.binary_file).expect("failed to run");

output.status.code().unwrap()
}

#[allow(unused)] // false positive
//#[cfg(test)] //TODO It should solve the warning but it doesn't
#[track_caller]
pub fn compile_and_run_with_args(
source: &str,
name: &str,
library: bool,
optlevel: OptLevel,
args: &CompilerArgs,
) -> Result<Output, Box<dyn std::error::Error>> {
let compile_result = compile_program_with_args(source, name, library, optlevel, args);
match compile_result {
//Err(e) => Err(std::error::Error::new(std::io::ErrorKind::Other, e.to_string())),
Err(e) => Err(e),
Ok(result) => {
let run_output = run_program(&result.binary_file)?;
Ok(run_output)
}
}
}

#[allow(unused)] // false positive
#[track_caller]
pub fn compile_and_run_output(
Expand Down
Loading
Loading