Skip to content

Commit

Permalink
Simplify data model by removing SetInt + renaming
Browse files Browse the repository at this point in the history
This commit starts simplifying the data model by removing `SetLit` which doesn't provide much benefit compared to inlining `SetIntLit` and `SetIntFloat` in `BasicLitExpr` (which is renamed `Literal`). It also makes `rangeInt` and `rangeFloat` private as these are intermediary struct that do not end-up in `fzn.Model`.
  • Loading branch information
rhartert committed May 27, 2024
1 parent a11f3c3 commit 78bccdf
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 246 deletions.
6 changes: 3 additions & 3 deletions fzn/anns.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ func parseAnnExpr(p *parser) ([]AnnExpr, error) {

func basicAnnExpr(p *parser) (*AnnExpr, error) {
switch {
case isBasicLiteralExpr(p):
ble, err := parseBasicLiteralExpr(p)
case isLiteral(p):
ble, err := parseLiteral(p)
if err != nil {
return nil, err
}
return &AnnExpr{BasicLitExpr: &ble}, nil
return &AnnExpr{Literal: &ble}, nil
case isIdentifier(p):
if p.lookAhead(1).Type == tok.TupleStart {
a, err := parseAnnotation(p)
Expand Down
8 changes: 4 additions & 4 deletions fzn/anns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func TestParserInstruction_parseAnnotation(t *testing.T) {
want: Annotation{
Identifier: "foo",
Exprs: [][]AnnExpr{{{
BasicLitExpr: &BasicLitExpr{
Literal: &Literal{
Int: ptr.Of(42),
},
}}},
Expand All @@ -178,7 +178,7 @@ func TestParserInstruction_parseAnnotation(t *testing.T) {
want: Annotation{
Identifier: "foo",
Exprs: [][]AnnExpr{
{{BasicLitExpr: &BasicLitExpr{Int: ptr.Of(42)}}},
{{Literal: &Literal{Int: ptr.Of(42)}}},
{{VarID: ptr.Of("bar")}},
},
},
Expand All @@ -200,11 +200,11 @@ func TestParserInstruction_parseAnnotation(t *testing.T) {
want: Annotation{
Identifier: "foo",
Exprs: [][]AnnExpr{
{{BasicLitExpr: &BasicLitExpr{Int: ptr.Of(42)}}},
{{Literal: &Literal{Int: ptr.Of(42)}}},
{{Annotation: &Annotation{
Identifier: "bar",
Exprs: [][]AnnExpr{{
{BasicLitExpr: &BasicLitExpr{Int: ptr.Of(1337)}},
{Literal: &Literal{Int: ptr.Of(1337)}},
}},
}}},
},
Expand Down
46 changes: 2 additions & 44 deletions fzn/basics.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,9 @@ func parseBasicExpr(p *parser) (BasicExpr, error) {
return BasicExpr{Identifier: t.Value}, nil
}

le, err := parseBasicLiteralExpr(p)
le, err := parseLiteral(p)
if err != nil {
return BasicExpr{}, fmt.Errorf("invalid basic expression: %w", err)
}
return BasicExpr{LiteralExpr: le}, nil
}

func isBasicLiteralExpr(p *parser) bool {
switch p.lookAhead(0).Type {
case tok.BoolLit, tok.IntLit, tok.FloatLit:
return true
default:
return isSetLit(p)
}
}

func parseBasicLiteralExpr(p *parser) (BasicLitExpr, error) {
if isSetLit(p) {
s, err := parseSetLit(p)
if err != nil {
return BasicLitExpr{}, err
}
return BasicLitExpr{Set: &s}, nil
}

switch tt := p.lookAhead(0).Type; tt {
case tok.BoolLit:
b, err := parseBoolLit(p)
if err != nil {
return BasicLitExpr{}, err
}
return BasicLitExpr{Bool: &b}, nil
case tok.IntLit:
i, err := parseIntLit(p)
if err != nil {
return BasicLitExpr{}, err
}
return BasicLitExpr{Int: &i}, nil
case tok.FloatLit:
f, err := parseFloatLit(p)
if err != nil {
return BasicLitExpr{}, err
}
return BasicLitExpr{Float: &f}, nil
default:
return BasicLitExpr{}, fmt.Errorf("token is not part of valid literal: %s", tt)
}
return BasicExpr{Literal: le}, nil
}
220 changes: 110 additions & 110 deletions fzn/fzn_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@ import (
"github.com/rhartert/ptr"
)

type testCaseModel struct {
desc string
input string
want *Model
wantErr bool
}

var testCakesFZN = `
array [1..2] of int: X_INTRODUCED_2_ = [250,200];
array [1..2] of int: X_INTRODUCED_6_ = [75,150];
Expand All @@ -30,117 +23,124 @@ constraint int_lin_eq([400,450,-1],[b,c,X_INTRODUCED_0_],0):: ctx_pos:: defines_
solve maximize X_INTRODUCED_0_;
`

var testCases = []testCaseModel{
{
desc: "cake.fzn",
input: testCakesFZN,
want: &Model{
Parameters: []Parameter{
{
Identifier: "X_INTRODUCED_2_",
Array: &Array{Start: 1, End: 2},
Type: ParTypeInt,
Exprs: []BasicLitExpr{
{Int: ptr.Of(250)},
{Int: ptr.Of(200)},
},
},
{
Identifier: "X_INTRODUCED_6_",
Array: &Array{Start: 1, End: 2},
Type: ParTypeInt,
Exprs: []BasicLitExpr{
{Int: ptr.Of(75)},
{Int: ptr.Of(150)},
},
},
{
Identifier: "X_INTRODUCED_8_",
Array: &Array{Start: 1, End: 2},
Type: ParTypeInt,
Exprs: []BasicLitExpr{
{Int: ptr.Of(100)},
{Int: ptr.Of(150)},
},
},
var testCakesModel = Model{
Parameters: []Parameter{
{
Identifier: "X_INTRODUCED_2_",
Array: &Array{Start: 1, End: 2},
Type: ParTypeInt,
Exprs: []Literal{
{Int: ptr.Of(250)},
{Int: ptr.Of(200)},
},
Variables: []Variable{
{
Identifier: "b",
Type: VarTypeIntRange,
Domain: VarDomain{IntDomain: &SetIntLit{Values: [][]int{{0, 3}}}},
Annotations: []Annotation{{Identifier: "output_var"}},
},
{
Identifier: "c",
Type: VarTypeIntRange,
Domain: VarDomain{IntDomain: &SetIntLit{Values: [][]int{{0, 6}}}},
Annotations: []Annotation{{Identifier: "output_var"}},
},
{
Identifier: "X_INTRODUCED_0_",
Type: VarTypeIntRange,
Domain: VarDomain{IntDomain: &SetIntLit{Values: [][]int{{0, 85000}}}},
Annotations: []Annotation{{Identifier: "is_defined_var"}},
},
},
{
Identifier: "X_INTRODUCED_6_",
Array: &Array{Start: 1, End: 2},
Type: ParTypeInt,
Exprs: []Literal{
{Int: ptr.Of(75)},
{Int: ptr.Of(150)},
},
Constraints: []Constraint{
{
Identifier: "int_lin_le",
Expressions: []Expr{
{Exprs: []BasicExpr{{Identifier: "X_INTRODUCED_2_"}}},
{IsArray: true, Exprs: []BasicExpr{{Identifier: "b"}, {Identifier: "c"}}},
{Exprs: []BasicExpr{{LiteralExpr: BasicLitExpr{Int: ptr.Of(4000)}}}},
},
},
{
Identifier: "int_lin_le",
Expressions: []Expr{
{Exprs: []BasicExpr{{Identifier: "X_INTRODUCED_6_"}}},
{IsArray: true, Exprs: []BasicExpr{{Identifier: "b"}, {Identifier: "c"}}},
{Exprs: []BasicExpr{{LiteralExpr: BasicLitExpr{Int: ptr.Of(2000)}}}},
},
},
{
Identifier: "int_lin_le",
Expressions: []Expr{
{Exprs: []BasicExpr{{Identifier: "X_INTRODUCED_8_"}}},
{IsArray: true, Exprs: []BasicExpr{{Identifier: "b"}, {Identifier: "c"}}},
{Exprs: []BasicExpr{{LiteralExpr: BasicLitExpr{Int: ptr.Of(500)}}}},
},
},
{
Identifier: "int_lin_eq",
Expressions: []Expr{
{IsArray: true, Exprs: []BasicExpr{
{LiteralExpr: BasicLitExpr{Int: ptr.Of(400)}},
{LiteralExpr: BasicLitExpr{Int: ptr.Of(450)}},
{LiteralExpr: BasicLitExpr{Int: ptr.Of(-1)}},
}},
{IsArray: true, Exprs: []BasicExpr{
{Identifier: "b"},
{Identifier: "c"},
{Identifier: "X_INTRODUCED_0_"},
}},
{Exprs: []BasicExpr{{LiteralExpr: BasicLitExpr{Int: ptr.Of(0)}}}},
},
Annotations: []Annotation{
{Identifier: "ctx_pos"},
{Identifier: "defines_var", Exprs: [][]AnnExpr{
{{VarID: ptr.Of("X_INTRODUCED_0_")}},
}},
},
},
},
{
Identifier: "X_INTRODUCED_8_",
Array: &Array{Start: 1, End: 2},
Type: ParTypeInt,
Exprs: []Literal{
{Int: ptr.Of(100)},
{Int: ptr.Of(150)},
},
SolveGoals: []SolveGoal{{
SolveMethod: SolveMethodMaximize,
Objective: BasicExpr{Identifier: "X_INTRODUCED_0_"},
}},
},
},
Variables: []Variable{
{
Identifier: "b",
Type: VarTypeIntRange,
Domain: VarDomain{IntDomain: &SetIntLit{Values: [][]int{{0, 3}}}},
Annotations: []Annotation{{Identifier: "output_var"}},
},
{
Identifier: "c",
Type: VarTypeIntRange,
Domain: VarDomain{IntDomain: &SetIntLit{Values: [][]int{{0, 6}}}},
Annotations: []Annotation{{Identifier: "output_var"}},
},
{
Identifier: "X_INTRODUCED_0_",
Type: VarTypeIntRange,
Domain: VarDomain{IntDomain: &SetIntLit{Values: [][]int{{0, 85000}}}},
Annotations: []Annotation{{Identifier: "is_defined_var"}},
},
},
Constraints: []Constraint{
{
Identifier: "int_lin_le",
Expressions: []Expr{
{Exprs: []BasicExpr{{Identifier: "X_INTRODUCED_2_"}}},
{IsArray: true, Exprs: []BasicExpr{{Identifier: "b"}, {Identifier: "c"}}},
{Exprs: []BasicExpr{{Literal: Literal{Int: ptr.Of(4000)}}}},
},
},
{
Identifier: "int_lin_le",
Expressions: []Expr{
{Exprs: []BasicExpr{{Identifier: "X_INTRODUCED_6_"}}},
{IsArray: true, Exprs: []BasicExpr{{Identifier: "b"}, {Identifier: "c"}}},
{Exprs: []BasicExpr{{Literal: Literal{Int: ptr.Of(2000)}}}},
},
},
{
Identifier: "int_lin_le",
Expressions: []Expr{
{Exprs: []BasicExpr{{Identifier: "X_INTRODUCED_8_"}}},
{IsArray: true, Exprs: []BasicExpr{{Identifier: "b"}, {Identifier: "c"}}},
{Exprs: []BasicExpr{{Literal: Literal{Int: ptr.Of(500)}}}},
},
},
{
Identifier: "int_lin_eq",
Expressions: []Expr{
{IsArray: true, Exprs: []BasicExpr{
{Literal: Literal{Int: ptr.Of(400)}},
{Literal: Literal{Int: ptr.Of(450)}},
{Literal: Literal{Int: ptr.Of(-1)}},
}},
{IsArray: true, Exprs: []BasicExpr{
{Identifier: "b"},
{Identifier: "c"},
{Identifier: "X_INTRODUCED_0_"},
}},
{Exprs: []BasicExpr{{Literal: Literal{Int: ptr.Of(0)}}}},
},
Annotations: []Annotation{
{Identifier: "ctx_pos"},
{Identifier: "defines_var", Exprs: [][]AnnExpr{
{{VarID: ptr.Of("X_INTRODUCED_0_")}},
}},
},
},
},
SolveGoals: []SolveGoal{{
SolveMethod: SolveMethodMaximize,
Objective: BasicExpr{Identifier: "X_INTRODUCED_0_"},
}},
}

func TestParseModel(t *testing.T) {
testCases := []struct {
desc string
input string
want *Model
wantErr bool
}{
{
desc: "cakes.fzn",
input: testCakesFZN,
want: &testCakesModel,
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
got, gotErr := ParseModel(strings.NewReader(tc.input))
Expand Down
Loading

0 comments on commit 78bccdf

Please sign in to comment.