Skip to content

Commit 884868e

Browse files
authored
Merge pull request #111 from Shoooooon/main
Support parametric sorts in the JSON format (and initial ArraysEx support)
2 parents 31624ca + a828b3e commit 884868e

9 files changed

Lines changed: 270 additions & 9 deletions

File tree

IntegrationTests/data/array.sem

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
(declare-term-types
2+
((E 0) (Start 0))
3+
((($IBVVary )
4+
($bvsub E E)
5+
($bvadd E E)
6+
($IBVVarx ))
7+
(($bv=x E))))
8+
9+
10+
11+
(define-funs-rec
12+
((E.Sem ((E_term_0 E) (r__0 (_ BitVec 32)) (rv (Array Int Int)) (x (_ BitVec 32)) (y (_ BitVec 32))) Bool)
13+
(Start.Sem ((Start_term_0 Start) (x_r0 (_ BitVec 32)) (y_r0 (_ BitVec 32)) (rq (Array Int Int)) (x (_ BitVec 32)) (y (_ BitVec 32))) Bool))
14+
15+
((match E_term_0
16+
(($IBVVary (exists ((r__1 (_ BitVec 32))) (and (= r__0 r__1)
17+
(= r__1 y))))
18+
(($bvsub E_term_1 E_term_2) (exists ((r__1 (_ BitVec 32)) (r__2 (_ BitVec 32)) (rb (Array Int Int))) (and (= r__0 (bvadd r__1 (bvneg r__2)))
19+
(E.Sem E_term_1 r__1 rb x y)
20+
(E.Sem E_term_2 r__2 rb x y))))
21+
(($bvadd E_term_1 E_term_2) (exists ((r__1 (_ BitVec 32)) (r__2 (_ BitVec 32)) (rb (Array Int Int))) (and (= r__0 (bvadd r__1 r__2))
22+
(E.Sem E_term_1 r__1 rb x y)
23+
(E.Sem E_term_2 r__2 rb x y))))
24+
($IBVVarx (exists ((r__1 (_ BitVec 32))) (and (= r__0 r__1)
25+
(= r__1 x))))))
26+
(match Start_term_0
27+
((($bv=x E_term_1) (exists ((r__1 (_ BitVec 32)) (rb (Array Int Int))) (and (and (= x_r0 r__1)
28+
(and (= rb rb) (= y y_r0)))
29+
(E.Sem E_term_1 r__1 rb x y))))))))
30+
31+
32+
(synth-fun BVtest_ADD_01() Start)
33+
34+
35+
(constraint (exists ((rq (Array Int Int)) (y (_ BitVec 32))) (Start.Sem BVtest_ADD_01 #x00000004 #x00000004 rq #x00000003 y)))
36+
37+
(check-synth)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
--format
2+
json
3+
--mode
4+
batch
5+
--
6+
data/array.sem

IntegrationTests/tests/test-json-array.txt

Lines changed: 19 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ This project is under active development and does not yet support all SMT-LIB2 f
3131
* Strings (with partial support for regular expressions)
3232
* Bit vectors (partial support; only theory functions supported for now)
3333
* Datatypes (non-parametric only)
34+
* Arrays (partial support)
3435

3536
Other features:
3637
* Converting SyGuS problems to CHCs on the fly (beta)
@@ -42,14 +43,12 @@ New additions:
4243
* Arbitrary `match` expressions
4344

4445
Unsupported SMT-LIB2 features include:
45-
* Parametric sorts
4646
* Theory functions annotated with `:left-assoc`, `:right-assoc`, `:chainable`, and `:pairwise`. Certain Core functions are implemented, so post an issue if others are needed.
4747
* Some terms, including `let`
4848
* Uninterpreted sorts (`declare-sort`) and sort aliases (`define-sort`)
4949

5050
The roadmap for next-up features includes:
5151
* Arbitrary `let` terms
52-
* Parameteric sorts
5352

5453
If there is an unsupported feature that you would like added, drop us a line by submitting an issue (or commenting on an existing one).
5554
This will help us prioritize what to put on our roadmap.

Semgus-Lib/Model/Smt/SmtCommonIdentifiers.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public static class SmtCommonIdentifiers
1616
public static SmtIdentifier StringsTheoryId { get; } = new("Strings");
1717
public static SmtIdentifier BitVectorsTheoryId { get; } = new("BitVectors");
1818
public static SmtIdentifier BitVectorsExtensionId { get; } = new("BitVectors", "extension");
19+
public static SmtIdentifier ArraysExTheoryId { get; } = new("ArraysEx");
1920

2021
public static SmtSortIdentifier BoolSortId { get; } = new("Bool");
2122
public static SmtSortIdentifier IntSortId { get; } = new("Int");
@@ -32,6 +33,7 @@ public SmtSortIdentifier this[int size]
3233
new SmtIdentifier.Index(size)));
3334
}
3435
}
36+
public static SmtIdentifier ArraySortPrimaryId { get; } = new("Array");
3537

3638
public static SmtIdentifier AndFunctionId { get; } = new("and");
3739
public static SmtIdentifier OrFunctionId { get; } = new("or");

Semgus-Lib/Model/Smt/SmtContext.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public SmtContext()
6464
SmtCoreTheory.Instance,
6565
SmtIntsTheory.Instance,
6666
SmtStringsTheory.Instance,
67-
SmtBitVectorsTheory.Instance
67+
SmtBitVectorsTheory.Instance,
68+
SmtArraysExTheory.Instance
6869
};
6970

7071
_extensions = new HashSet<ISmtExtension>()
@@ -249,7 +250,7 @@ private bool TryResolveSortParameters(SmtSortIdentifier id, SmtSort candidate, [
249250
return false;
250251
}
251252

252-
if (candidate.Arity == 0)
253+
if (candidate.Arity == 0 || !candidate.IsParametric)
253254
{
254255
resolved = candidate;
255256
error = default;
@@ -266,13 +267,16 @@ private bool TryResolveSortParameters(SmtSortIdentifier id, SmtSort candidate, [
266267
else
267268
{
268269
resolved = default;
270+
error = $"Unable to resolve sort parameter {child.Name} in parametric sort {id.Name}: {error}";
269271
return false;
270272
}
271273
}
272274

273-
resolved = default;
274-
error = "Not finished being implemented";
275-
return false;
275+
candidate.UpdateForResolvedParameters(resolvedSubsorts);
276+
277+
resolved = candidate;
278+
error = "";
279+
return true;
276280
}
277281

278282
public void Push()

Semgus-Lib/Model/Smt/SmtSort.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public SmtSort(SmtSortIdentifier name)
2727
public SmtSortIdentifier Name { get; }
2828

2929
/// <summary>
30-
/// Does this sort have parameters?
30+
/// Does this sort have parameters that need to be resolved?
3131
/// </summary>
3232
public bool IsParametric { get; protected set; } = false;
3333

@@ -41,6 +41,12 @@ public SmtSort(SmtSortIdentifier name)
4141
/// </summary>
4242
public int Arity { get; protected set; } = 0;
4343

44+
/// <summary>
45+
/// Updates this sort for resolved parameters
46+
/// </summary>
47+
/// <param name="resolved">Resolved parameters. Should have same length as arity</param>
48+
public virtual void UpdateForResolvedParameters(IList<SmtSort> resolved) { }
49+
4450
/// <summary>
4551
/// An arbitrary generic sort
4652
/// </summary>
@@ -54,6 +60,28 @@ public GenericSort(SmtSortIdentifier name) : base(name)
5460
{ }
5561
}
5662

63+
/// <summary>
64+
/// A sort parameter that needs to be resolved to a real sort
65+
/// </summary>
66+
internal class UnresolvedParameterSort : SmtSort
67+
{
68+
/// <summary>
69+
/// Identifier that needs to be resolved
70+
/// </summary>
71+
public SmtSortIdentifier Identifier { get; }
72+
73+
/// <summary>
74+
/// Creates a new unresolved sort. This is a placeholder for sort parameters to be resolved.
75+
/// </summary>
76+
/// <param name="identifier">Sort identifier to resolve</param>
77+
public UnresolvedParameterSort(SmtSortIdentifier identifier) : base(identifier)
78+
{
79+
Identifier = identifier;
80+
IsSortParameter = true;
81+
Arity = identifier.Arity;
82+
}
83+
}
84+
5785
/// <summary>
5886
/// A sort containing wildcard parameters. Useful in rank templates.
5987
/// Indices in the sort name may be '*', which will match anything.
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
using Semgus.Model.Smt.Terms;
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Diagnostics.CodeAnalysis;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
using static Semgus.Model.Smt.SmtCommonIdentifiers;
11+
12+
namespace Semgus.Model.Smt.Theories
13+
{
14+
/// <summary>
15+
/// The theory of arrays with extensions
16+
/// </summary>
17+
internal class SmtArraysExTheory : ISmtTheory
18+
{
19+
/// <summary>
20+
/// A singleton theory instance
21+
/// </summary>
22+
public static SmtArraysExTheory Instance { get; } = new();
23+
24+
/// <summary>
25+
/// Underlying array sort
26+
/// </summary>
27+
internal sealed class ArraySort : SmtSort
28+
{
29+
/// <summary>
30+
/// Cache of instantiated sorts. We need this since sorts are compared by reference
31+
/// </summary>
32+
private static readonly IDictionary<(SmtSortIdentifier, SmtSortIdentifier), ArraySort> _sortCache
33+
= new Dictionary<(SmtSortIdentifier, SmtSortIdentifier), ArraySort>();
34+
35+
/// <summary>
36+
/// The sort used for indexing the array
37+
/// </summary>
38+
public SmtSort IndexSort { get; private set; }
39+
40+
/// <summary>
41+
/// The sort used for the array element values
42+
/// </summary>
43+
public SmtSort ValueSort { get; private set; }
44+
45+
/// <summary>
46+
/// Constructs a new array sort with the given parameters
47+
/// </summary>
48+
/// <param name="size">Size of bit vectors in this sort</param>
49+
private ArraySort(SmtSortIdentifier indexSort, SmtSortIdentifier valueSort) :
50+
base(new(new SmtIdentifier(ArraySortPrimaryId.Symbol), indexSort, valueSort))
51+
{
52+
IndexSort = new UnresolvedParameterSort(indexSort);
53+
ValueSort = new UnresolvedParameterSort(valueSort);
54+
IsParametric = true;
55+
Arity = 2;
56+
}
57+
58+
/// <summary>
59+
/// Gets the array sort for the given index and value sorts
60+
/// </summary>
61+
/// <param name="index">The index sort to use</param>
62+
/// <param name="value">The value sort to use</param>
63+
/// <returns>The array sort for the given index and value sorts</returns>
64+
public static ArraySort GetSort(SmtSortIdentifier index, SmtSortIdentifier value)
65+
{
66+
if (_sortCache.TryGetValue((index, value), out ArraySort? sort))
67+
{
68+
return sort;
69+
}
70+
else
71+
{
72+
sort = new ArraySort(index, value);
73+
_sortCache.Add((index, value), sort);
74+
return sort;
75+
}
76+
}
77+
78+
/// <summary>
79+
/// Updates this sort with the resolved parameteric sorts
80+
/// </summary>
81+
/// <param name="resolved">Resolved parameters. Must have arity 2</param>
82+
public override void UpdateForResolvedParameters(IList<SmtSort> resolved)
83+
{
84+
if (resolved.Count != 2)
85+
{
86+
throw new InvalidOperationException("Got list of resolved sorts not of length 2!");
87+
}
88+
89+
IndexSort = resolved[0];
90+
ValueSort = resolved[1];
91+
}
92+
}
93+
94+
/// <summary>
95+
/// This theory's name
96+
/// </summary>
97+
public SmtIdentifier Name { get; } = ArraysExTheoryId;
98+
99+
#region Deprecated
100+
public IReadOnlyDictionary<SmtIdentifier, IApplicable> Functions { get; }
101+
#endregion
102+
103+
/// <summary>
104+
/// The primary (i.e., non-indexed) sort symbols (e.g., "Array")
105+
/// </summary>
106+
public IReadOnlySet<SmtIdentifier> PrimarySortSymbols { get; }
107+
108+
/// <summary>
109+
/// The primary (i.e., non-indexed) function symbols
110+
/// </summary>
111+
public IReadOnlySet<SmtIdentifier> PrimaryFunctionSymbols { get; }
112+
113+
/// <summary>
114+
/// Constructs an instance of the theory of arrays
115+
/// </summary>
116+
/// <param name="core">Reference to the core theory</param>
117+
private SmtArraysExTheory()
118+
{
119+
SmtSourceBuilder sb = new(this);
120+
sb.AddOnTheFlyFn("select");
121+
sb.AddOnTheFlyFn("store");
122+
123+
Functions = sb.Functions;
124+
PrimaryFunctionSymbols = sb.PrimaryFunctionSymbols;
125+
PrimarySortSymbols = new HashSet<SmtIdentifier>() { ArraySortPrimaryId };
126+
}
127+
128+
/// <summary>
129+
/// Looks up a sort symbol in this theory
130+
/// </summary>
131+
/// <param name="sortId">The sort ID</param>
132+
/// <param name="resolvedSort">The resolved sort</param>
133+
/// <returns>True if successfully gotten</returns>
134+
public bool TryGetSort(SmtSortIdentifier sortId, [NotNullWhen(true)] out SmtSort? resolvedSort)
135+
{
136+
if (sortId.Arity == 2 && sortId.Name == ArraySortPrimaryId)
137+
{
138+
resolvedSort = ArraySort.GetSort(sortId.Parameters[0], sortId.Parameters[1]);
139+
return true;
140+
}
141+
resolvedSort = default;
142+
return false;
143+
}
144+
145+
/// <summary>
146+
/// Looks up a function in this theory
147+
/// </summary>
148+
/// <param name="functionId">The function ID to look up</param>
149+
/// <param name="resolvedFunction">The resolved function</param>
150+
/// <returns>True if successfully gotten</returns>
151+
public bool TryGetFunction(SmtIdentifier functionId, [NotNullWhen(true)] out IApplicable? resolvedFunction)
152+
{
153+
return Functions.TryGetValue(functionId, out resolvedFunction);
154+
}
155+
}
156+
}

SemgusParser/Json/Converters/SmtSortIdentifierConverter.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,17 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer
3131

3232
if (id.Parameters.Length > 0)
3333
{
34-
throw new InvalidOperationException("Parameterized sorts not yet supported by the JSON serializer.");
34+
writer.WriteStartObject();
35+
writer.WritePropertyName("kind");
36+
serializer.Serialize(writer, id.Name);
37+
writer.WritePropertyName("params");
38+
writer.WriteStartArray();
39+
foreach (var sort in id.Parameters)
40+
{
41+
serializer.Serialize(writer, sort);
42+
}
43+
writer.WriteEndArray();
44+
writer.WriteEndObject();
3545
}
3646
else
3747
{

0 commit comments

Comments
 (0)