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

Model parsing from JSON #32

Merged
merged 36 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c132b2b
Add parsers directory
lixitrixi Oct 30, 2023
25478f7
Initial parser code
lixitrixi Nov 2, 2023
67eab45
Compact syntax and supporting Model constructor
lixitrixi Nov 3, 2023
8960e0c
Format code
lixitrixi Nov 3, 2023
9477ca4
Update crate structure and imports
lixitrixi Nov 6, 2023
63868fd
Add Conjure Error and edit crate structure (broken)
lixitrixi Nov 8, 2023
2fede22
Possible import fix (@niklasdewally)
lixitrixi Nov 8, 2023
a179204
Merge branch 'conjure-cp:main' into main
lixitrixi Nov 8, 2023
bea115d
Clearly separate packages and workspace
lixitrixi Nov 8, 2023
1c2e40f
Add default run target
lixitrixi Nov 8, 2023
dda39b0
Merge branch 'workspace-refactor' into json-parsing
lixitrixi Nov 12, 2023
e301bb1
Merge refactoring of project structure
lixitrixi Nov 13, 2023
6ae8037
Merge remote-tracking branch 'upstream/main' into main
lixitrixi Nov 13, 2023
4a5cac1
Merge branch 'main' into json-parsing
lixitrixi Nov 13, 2023
6f62229
Resolve import conflicts
lixitrixi Nov 13, 2023
fb5726c
Update Error code to use thiserror
lixitrixi Nov 14, 2023
6f5480f
Parse JSON in main
lixitrixi Nov 14, 2023
42222ff
Assert manual and parsed models are equal
lixitrixi Nov 14, 2023
a3706ae
Format model output strings
lixitrixi Nov 14, 2023
b86588b
Update output formatting
lixitrixi Nov 14, 2023
a395036
Fix format fails
lixitrixi Nov 14, 2023
4a571d1
Use thiserror to create From<> impl
lixitrixi Nov 14, 2023
98f09dc
Update gitignore
lixitrixi Nov 14, 2023
4354d92
Update error and clean parsing code
lixitrixi Nov 14, 2023
d628d20
Parse variable domains
lixitrixi Nov 14, 2023
d7da76b
Add integration test foundation
lixitrixi Nov 14, 2023
bb7b7a4
Cargo format
lixitrixi Nov 14, 2023
32b0bbf
Parser syntax tweaks
lixitrixi Nov 14, 2023
58fbcfa
Complete integration tests
lixitrixi Nov 19, 2023
2c95df3
Attempt CI fix
lixitrixi Nov 20, 2023
149229a
Silence test failures (for now)
lixitrixi Nov 20, 2023
58ba655
Cargo format
lixitrixi Nov 20, 2023
e9d0407
Merge branch 'main' into json-parsing
lixitrixi Nov 20, 2023
0c6810d
Fix i32/i64 discrepancy
lixitrixi Nov 20, 2023
dc055c1
Fix build dependency versions
lixitrixi Nov 20, 2023
7ae4d3a
Merge branch 'main' into json-parsing
lixitrixi Nov 20, 2023
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
47 changes: 47 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ edition = "2021"
[workspace]
members = ["solvers/kissat", "solvers/minion", "solvers/chuffed"]
exclude = []

[dependencies]
serde = { version = "1.0.190", features = ["derive"] }
serde_json = "1.0.108"
5 changes: 5 additions & 0 deletions examples/abc.essence
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
find a,b,c : int(1..3)
such that a + b + c = 4
such that a >= b

$ conjure pretty --output-format=astjson examples/abc.essence > examples/abc.json
62 changes: 62 additions & 0 deletions examples/abc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{"mInfo":
{"finds": [], "givens": [], "enumGivens": [], "enumLettings": [], "lettings": [], "unnameds": [],
"strategyQ": {"Auto": {"Interactive": []}}, "strategyA": {"Auto": {"Interactive": []}}, "trailCompact": [],
"nameGenState": [], "nbExtraGivens": 0, "representations": [], "representationsTree": [], "originalDomains": [],
"trailGeneralised": [], "trailVerbose": [], "trailRewrites": []},
"mLanguage": {"language": {"Name": "Essence"}, "version": [1, 3]},
"mStatements":
[{"Declaration":
{"FindOrGiven":
["Find", {"Name": "a"},
{"DomainInt":
[{"TagInt": []},
[{"RangeBounded":
[{"Constant": {"ConstantInt": [{"TagInt": []}, 1]}},
{"Constant": {"ConstantInt": [{"TagInt": []}, 3]}}]}]]}]}},
{"Declaration":
{"FindOrGiven":
["Find", {"Name": "b"},
{"DomainInt":
[{"TagInt": []},
[{"RangeBounded":
[{"Constant": {"ConstantInt": [{"TagInt": []}, 1]}},
{"Constant": {"ConstantInt": [{"TagInt": []}, 3]}}]}]]}]}},
{"Declaration":
{"FindOrGiven":
["Find", {"Name": "c"},
{"DomainInt":
[{"TagInt": []},
[{"RangeBounded":
[{"Constant": {"ConstantInt": [{"TagInt": []}, 1]}},
{"Constant": {"ConstantInt": [{"TagInt": []}, 3]}}]}]]}]}},
{"SuchThat":
[{"Op":
{"MkOpEq":
[{"Op":
{"MkOpSum":
{"AbstractLiteral":
{"AbsLitMatrix":
[{"DomainInt":
[{"TagInt": []},
[{"RangeBounded":
[{"Constant": {"ConstantInt": [{"TagInt": []}, 1]}},
{"Constant": {"ConstantInt": [{"TagInt": []}, 2]}}]}]]},
[{"Op":
{"MkOpSum":
{"AbstractLiteral":
{"AbsLitMatrix":
[{"DomainInt":
[{"TagInt": []},
[{"RangeBounded":
[{"Constant":
{"ConstantInt":
[{"TagInt": []}, 1]}},
{"Constant":
{"ConstantInt":
[{"TagInt": []}, 2]}}]}]]},
[{"Reference": [{"Name": "a"}, null]},
{"Reference": [{"Name": "b"}, null]}]]}}}},
{"Reference": [{"Name": "c"}, null]}]]}}}},
{"Constant": {"ConstantInt": [{"TagInt": []}, 4]}}]}}]},
{"SuchThat":
[{"Op": {"MkOpGeq": [{"Reference": [{"Name": "a"}, null]}, {"Reference": [{"Name": "b"}, null]}]}}]}]}
7 changes: 7 additions & 0 deletions src/common/ast/ast.rs → src/ast/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ pub struct Model {
}

impl Model {
pub fn new() -> Self {
Model {
variables: HashMap::new(),
constraints: Vec::new(),
}
}

// Function to update a DecisionVariable based on its Name
pub fn update_domain(&mut self, name: &Name, new_domain: Domain) {
if let Some(decision_var) = self.variables.get_mut(name) {
Expand Down
File renamed without changes.
1 change: 0 additions & 1 deletion src/common/mod.rs

This file was deleted.

30 changes: 30 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use serde_json::Error as JsonError;
use std::fmt::Display;

pub enum Error {
Json(JsonError),
ParseError(String),
Generic(String),
}

impl From<JsonError> for Error {
fn from(e: JsonError) -> Self {
Error::Json(e)
}
}

impl From<&str> for Error {
fn from(e: &str) -> Self {
Error::Generic(e.to_owned())
}
}

impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match &self {
Error::Json(e) => write!(f, "serde_json error: {}", e),
Error::ParseError(e) => write!(f, "Parse error: {}", e),
Error::Generic(e) => write!(f, "Error: {}", e),
}
}
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
mod common;
pub use common::ast;
pub mod ast;
pub mod error;
pub mod parse;

pub use ast::Model;
pub use error::Error;
91 changes: 49 additions & 42 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,59 @@
use std::collections::HashMap;
use std::{collections::HashMap, fs::File, io::Read};

mod common;
use common::ast::*;
mod ast;
mod parse;
use {ast::Model, parse::*};

lixitrixi marked this conversation as resolved.
Show resolved Hide resolved
fn main() {
let mut abc = File::open("examples/abc.json").unwrap();
let mut abc_str = String::new();
abc.read_to_string(&mut abc_str).unwrap();

let m = Model::from_json(&abc_str);

// find a,b,c : int(1..3)
// such that a + b + c = 4
// such that a >= b

let a = Name::UserName(String::from("a"));
let b = Name::UserName(String::from("b"));
let c = Name::UserName(String::from("c"));
// let a = Name::UserName(String::from("a"));
// let b = Name::UserName(String::from("b"));
// let c = Name::UserName(String::from("c"));

let mut variables = HashMap::new();
variables.insert(
a.clone(),
DecisionVariable {
domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
},
);
variables.insert(
b.clone(),
DecisionVariable {
domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
},
);
variables.insert(
c.clone(),
DecisionVariable {
domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
},
);
// let mut variables = HashMap::new();
// variables.insert(
// a.clone(),
// DecisionVariable {
// domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
// },
// );
// variables.insert(
// b.clone(),
// DecisionVariable {
// domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
// },
// );
// variables.insert(
// c.clone(),
// DecisionVariable {
// domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
// },
// );

let mut m = Model {
variables,
constraints: vec![
Expression::Eq(
Box::new(Expression::Sum(vec![
Expression::Reference(a.clone()),
Expression::Reference(b.clone()),
Expression::Reference(c.clone()),
])),
Box::new(Expression::ConstantInt(4)),
),
Expression::Geq(
Box::new(Expression::Reference(a.clone())),
Box::new(Expression::Reference(b.clone())),
),
],
};
// let mut m = Model {
// variables,
// constraints: vec![
// Expression::Eq(
// Box::new(Expression::Sum(vec![
// Expression::Reference(a.clone()),
// Expression::Reference(b.clone()),
// Expression::Reference(c.clone()),
// ])),
// Box::new(Expression::ConstantInt(4)),
// ),
// Expression::Geq(
// Box::new(Expression::Reference(a.clone())),
// Box::new(Expression::Reference(b.clone())),
// ),
// ],
// };
}
28 changes: 28 additions & 0 deletions src/parse/json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::ast::Model;
use crate::error::Error;
use serde_json::Value as JsonValue;

pub fn parse_json(str: &String) -> Result<Model, Error> {
let v: JsonValue = serde_json::from_str(str)?;
let constraints: &Vec<JsonValue> = match &v["mStatements"] {
JsonValue::Array(a) => Ok(a),
_ => Err(Error::ParseError("mStatements is not an array".to_owned())),
}?;

let mut m = Model::new();
for c in constraints {
let obj = match c {
JsonValue::Object(obj) => Ok(obj),
_ => Err("Invalid JSON"),
}?;
println!("{:?}", c);
}

Ok(m)
}

impl Model {
pub fn from_json(str: &String) -> Result<Model, Error> {
parse_json(str)
}
}
3 changes: 3 additions & 0 deletions src/parse/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod json;

pub use json::parse_json;
17 changes: 4 additions & 13 deletions tests/model_tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Tests for various functionalities of the Model

use std::collections::HashMap;
use conjure_oxide::ast::*;
use std::collections::HashMap;

#[test]
fn modify_domain() {
Expand All @@ -11,25 +11,16 @@ fn modify_domain() {
let d2 = Domain::IntDomain(vec![Range::Bounded(1, 2)]);

let mut variables = HashMap::new();
variables.insert(
a.clone(),
DecisionVariable {
domain: d1.clone(),
},
);
variables.insert(a.clone(), DecisionVariable { domain: d1.clone() });

let mut m = Model {
variables,
constraints: Vec::new(),
};

assert!(
(*m.variables.get(&a).unwrap()).domain == d1
);
assert!((*m.variables.get(&a).unwrap()).domain == d1);

m.update_domain(&a, d2.clone());

assert!(
(*m.variables.get(&a).unwrap()).domain == d2
);
assert!((*m.variables.get(&a).unwrap()).domain == d2);
}
2 changes: 1 addition & 1 deletion tests/rewrite_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ fn simplify_expression(expr: Expression) -> Expression {
),
_ => expr,
}
}
}
Loading