flatzinc/
solve_items.rs

1use winnow::{
2    combinator::{alt, cut_err},
3    error::{AddContext, FromExternalError, ParserError, StrContext},
4    PResult, Parser,
5};
6
7use crate::{
8    comments::{space_or_comment0, space_or_comment1},
9    expressions::{
10        annotations, bool_expr, float_expr, int_expr, set_expr, Annotations, BoolExpr, FloatExpr,
11        IntExpr, SetExpr,
12    },
13};
14
15#[derive(PartialEq, Clone, Debug)]
16pub struct SolveItem {
17    pub goal: Goal,
18    pub annotations: Annotations,
19}
20
21pub fn solve_item<'a, E>(input: &mut &'a str) -> PResult<SolveItem, E>
22where
23    E: ParserError<&'a str>
24        + FromExternalError<&'a str, std::num::ParseIntError>
25        + FromExternalError<&'a str, std::num::ParseFloatError>
26        + AddContext<&'a str, StrContext>,
27{
28    space_or_comment0(input)?;
29    "solve".parse_next(input)?;
30    cut_err(solve_item_tail.context(StrContext::Label("Error while parsing solve statement")))
31        .parse_next(input)
32}
33pub fn solve_item_tail<'a, E>(input: &mut &'a str) -> PResult<SolveItem, E>
34where
35    E: ParserError<&'a str>
36        + FromExternalError<&'a str, std::num::ParseIntError>
37        + FromExternalError<&'a str, std::num::ParseFloatError>,
38{
39    space_or_comment1(input)?;
40    let annotations = annotations(input)?;
41    space_or_comment0(input)?;
42    let goal = alt((
43        satisfy,
44        optimize_bool,
45        optimize_int,
46        optimize_float,
47        optimize_set,
48    ))
49    .parse_next(input)?;
50    space_or_comment0(input)?;
51    ';'.parse_next(input)?;
52    space_or_comment0(input)?;
53    Ok(SolveItem { goal, annotations })
54}
55#[test]
56fn test_solve_item() {
57    use crate::solve_items::{Goal, OptimizationType};
58    use crate::{AnnExpr, Annotation, Expr};
59    use winnow::error::ContextError;
60    let mut input = "solve :: int_search(X_59,input_order,indomain_min,complete) minimize X_24;";
61    assert_eq!(
62        solve_item::<ContextError>(&mut input),
63        Ok(SolveItem {
64            goal: Goal::OptimizeBool(
65                OptimizationType::Minimize,
66                BoolExpr::VarParIdentifier("X_24".to_string())
67            ),
68            annotations: vec![Annotation {
69                id: "int_search".to_string(),
70                expressions: vec![
71                    AnnExpr::Expr(Expr::VarParIdentifier("X_59".to_string())),
72                    AnnExpr::Expr(Expr::VarParIdentifier("input_order".to_string())),
73                    AnnExpr::Expr(Expr::VarParIdentifier("indomain_min".to_string())),
74                    AnnExpr::Expr(Expr::VarParIdentifier("complete".to_string()))
75                ]
76            }]
77        })
78    );
79}
80
81#[derive(PartialEq, Clone, Debug)]
82pub enum Goal {
83    Satisfy,
84    OptimizeBool(OptimizationType, BoolExpr),
85    OptimizeInt(OptimizationType, IntExpr),
86    OptimizeFloat(OptimizationType, FloatExpr),
87    OptimizeSet(OptimizationType, SetExpr),
88}
89
90#[derive(PartialEq, Clone, Debug)]
91pub enum OptimizationType {
92    Minimize,
93    Maximize,
94}
95
96pub fn satisfy<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<Goal, E> {
97    "satisfy".parse_next(input)?;
98    Ok(Goal::Satisfy)
99}
100
101fn opt_type<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
102    alt((minimize, maximize)).parse_next(input)
103}
104
105fn minimize<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
106    "minimize".parse_next(input)?;
107    Ok(OptimizationType::Minimize)
108}
109
110fn maximize<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<OptimizationType, E> {
111    "maximize".parse_next(input)?;
112    Ok(OptimizationType::Maximize)
113}
114
115pub fn optimize_bool<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<Goal, E> {
116    let opt_type = opt_type(input)?;
117    space_or_comment1(input)?;
118    let be = bool_expr(input)?;
119    Ok(Goal::OptimizeBool(opt_type, be))
120}
121
122pub fn optimize_int<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
123where
124    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>,
125{
126    let opt_type = opt_type(input)?;
127    space_or_comment1(input)?;
128    let be = int_expr(input)?;
129    Ok(Goal::OptimizeInt(opt_type, be))
130}
131
132pub fn optimize_float<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
133where
134    E: ParserError<&'a str> + FromExternalError<&'a str, std::num::ParseFloatError>,
135{
136    let opt_type = opt_type(input)?;
137    space_or_comment1(input)?;
138    let be = float_expr(input)?;
139    Ok(Goal::OptimizeFloat(opt_type, be))
140}
141
142pub fn optimize_set<'a, E>(input: &mut &'a str) -> PResult<Goal, E>
143where
144    E: ParserError<&'a str>
145        + FromExternalError<&'a str, std::num::ParseIntError>
146        + FromExternalError<&'a str, std::num::ParseFloatError>,
147{
148    let opt_type = opt_type(input)?;
149    space_or_comment1(input)?;
150    let be = set_expr(input)?;
151    Ok(Goal::OptimizeSet(opt_type, be))
152}