{"id":22366073,"url":"https://github.com/microsoft/zen","last_synced_at":"2025-04-06T17:13:24.202Z","repository":{"id":38819705,"uuid":"258902015","full_name":"microsoft/Zen","owner":"microsoft","description":"Zen is a constraint solving library for .NET","archived":false,"fork":false,"pushed_at":"2024-01-08T18:23:22.000Z","size":1446,"stargazers_count":101,"open_issues_count":3,"forks_count":13,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-30T21:39:30.206Z","etag":null,"topics":["constraint","solving","verification","zen"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/microsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-26T00:19:34.000Z","updated_at":"2025-03-10T11:26:15.000Z","dependencies_parsed_at":"2025-01-22T09:07:46.350Z","dependency_job_id":"57834bf8-a47f-4c04-8d72-6bc4b84a4733","html_url":"https://github.com/microsoft/Zen","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FZen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FZen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FZen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FZen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/microsoft","download_url":"https://codeload.github.com/microsoft/Zen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247517922,"owners_count":20951719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["constraint","solving","verification","zen"],"created_at":"2024-12-04T18:07:35.776Z","updated_at":"2025-04-06T17:13:24.174Z","avatar_url":"https://github.com/microsoft.png","language":"C#","readme":"[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\r\n![Build Status](https://github.com/microsoft/Zen/actions/workflows/dotnet.yml/badge.svg)\r\n![badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/rabeckett/6623db8f2d0c01f6b2bc880e6219f97f/raw/code-coverage.json)\r\n\r\n# Introduction\r\nZen is a constraint solving library for .NET. Zen makes it easy to express high-level symbolic computations directly in .NET. It translates these symbolic expressions to low-level constraint solvers and then back to .NET objects. The Zen library comes equipped with a number of built-in tools for processing symbolic models, including a compiler (to .NET IL), an exhaustive model checker, and a test input generator. It supports multiple backends including one based on the Z3 SMT solver and another based on Binary Decision Diagrams (BDDs).\r\n\r\n# Table of contents\r\n- [Introduction](#introduction)\r\n- [Table of contents](#table-of-contents)\r\n- [Installation](#installation)\r\n- [Overview of Zen](#overview-of-zen)\r\n  - [Zen Expressions](#zen-expressions)\r\n  - [Executing a function](#executing-a-function)\r\n  - [Searching for inputs](#searching-for-inputs)\r\n  - [Computing with sets](#computing-with-sets)\r\n  - [Generating test inputs](#generating-test-inputs)\r\n  - [Optimization](#optimization)\r\n- [Supported data types](#supported-data-types)\r\n  - [Primitive types](#primitive-types)\r\n  - [Integer types](#integer-types)\r\n  - [Options, Tuples](#options-tuples)\r\n  - [Real Values](#real-values)\r\n  - [Finite Sequences, Bags, Maps](#finite-sequences-bags-maps)\r\n  - [Unbounded Sets and Maps](#unbounded-sets-and-maps)\r\n  - [Constant Sets and Maps](#constant-sets-and-maps)\r\n  - [Fixed Length Arrays](#fixed-length-arrays)\r\n  - [Sequences, Strings, and Regular Expressions](#sequences-strings-and-regular-expressions)\r\n  - [Custom classes and structs](#custom-classes-and-structs)\r\n  - [Enumerated values](#enumerated-values)\r\n- [Zen Attributes](#zen-attributes)\r\n- [Solver Backends](#solver-backends)\r\n- [Solver Timeouts](#solver-timeouts)\r\n- [Example: Network ACLs](#example-network-acls)\r\n- [Implementation Details](#implementation-details)\r\n- [Contributing](#contributing)\r\n\r\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\r\n# Installation\r\nJust add the project to your visual studio solution. Alternatively, a nuget package is available [here](https://www.nuget.org/packages/ZenLib).\r\n\r\n\u003ca name=\"overview-of-zen\"\u003e\u003c/a\u003e\r\n# Overview of Zen\r\n\r\nTo import the Zen library, add the following line to your source file:\r\n\r\n```csharp\r\nusing ZenLib;\r\n```\r\n\r\nMost library methods are found in the `Zen.*` namespace. To avoid having to write this prefix out every time, you can alternatively add the following using statement:\r\n\r\n```csharp\r\nusing static ZenLib.Zen;\r\n```\r\n\r\nThe Zen library provides the type `Zen\u003cT\u003e`, which represents a symbolic value of type `T`. The library can then solve constraints involving symbolic values. The following code shows a basic use of Zen -- it creates several symbolic variables of different types (e.g., `bool`, `int`, `string`, `FSeq` - finite sequences) and then encodes constraints over those variables.\r\n\r\n```csharp\r\n// create symbolic variables of different types\r\nvar b = Zen.Symbolic\u003cbool\u003e();\r\nvar i = Zen.Symbolic\u003cint\u003e();\r\nvar s = Zen.Symbolic\u003cstring\u003e();\r\nvar o = Zen.Symbolic\u003cOption\u003culong\u003e\u003e();\r\nvar l = Zen.Symbolic\u003cFSeq\u003cint\u003e\u003e(depth: 10);\r\n\r\n// build constraints on these variables\r\nvar c1 = Zen.Or(b, i \u003c= 10);\r\nvar c2 = Zen.Or(Zen.Not(b), o == Option.Some(1UL));\r\nvar c3 = Zen.Or(s.Contains(\"hello\"), o.IsNone());\r\nvar c4 = Zen.And(\r\n        l.Where(x =\u003e x == i).Length() == (BigInteger)5,\r\n        Zen.Not(l.All(x =\u003e x == i)));\r\nvar c5 = l.All(x =\u003e Zen.And(x \u003e= 0, x \u003c= 100));\r\n\r\n// solve the constraints to get a solution\r\nvar solution = Zen.And(c1, c2, c3, c4, c5).Solve();\r\n\r\nSystem.Console.WriteLine(\"b: \" + solution.Get(b));\r\nSystem.Console.WriteLine(\"i: \" + solution.Get(i));\r\nSystem.Console.WriteLine(\"s: \" + solution.Get(s));\r\nSystem.Console.WriteLine(\"o: \" + solution.Get(o));\r\nSystem.Console.WriteLine(\"l: \" + string.Join(\",\", solution.Get(l)));\r\n```\r\n\r\nAn example output is the following values:\r\n\r\n```csharp\r\nb: True\r\ni: 38\r\ns: hello\r\no: Some(1)\r\nl: [10,38,38,38,38,38]\r\n```\r\n\r\n\u003ca name=\"computing-with-zen-expressions\"\u003e\u003c/a\u003e\r\n## Zen Expressions\r\n\r\n`Zen\u003cT\u003e` objects are just normal .NET objects, we can pass them and return them from functions. For instance, the following code computes a new symbolic integer from two integer inputs `x` and `y`:\r\n\r\n```csharp\r\nZen\u003cint\u003e MultiplyAndAdd(Zen\u003cint\u003e x, Zen\u003cint\u003e y)\r\n{\r\n    return 3 * x + y;\r\n}\r\n```\r\n\r\nZen overloads common C# operators such as `\u0026,|,^,\u003c=, \u003c, \u003e, \u003e=, +, -, *, true, false` to work with Zen values and supports implicit conversions to lift C# values (of type `T`) to Zen values (of type `Zen\u003cT\u003e`). Zen can represent a \"function\" like the one above to perform various symbolic tasks by creating a `ZenFunction` to wrap the `MultiplyAndAdd` function:\r\n\r\n```csharp\r\nvar function = new ZenFunction\u003cint, int, int\u003e(MultiplyAndAdd);\r\n```\r\n\r\n\u003ca name=\"executing-a-function\"\u003e\u003c/a\u003e\r\n## Executing a function\r\n\r\nZen can execute the function we have built on inputs by calling the `Evaluate` method on the `ZenFunction`:\r\n\r\n```csharp\r\nvar output = function.Evaluate(3, 2); // output = 11\r\n```\r\n\r\nThis will interpret the expression tree created by the Zen function at runtime and return back a C# `int` value in this case. Of course interpreting a tree is quite slow compared to multiplying a few numbers, so if you need to execute a function many times, Zen can compile the model using the C# `System.Reflection.Emit` API. This generates IL instructions that execute efficiently - as if the function had been written using actual `int` values. Doing so is easy, just call the `Compile` method on the function first:\r\n\r\n```csharp\r\nfunction.Compile();\r\noutput = function.Evaluate(3, 2); // output = 11\r\n```\r\n\r\nOr alternatively:\r\n\r\n```csharp\r\nFunc\u003cint, int, int\u003e f = Zen.Compile(MultiplyAndAdd);\r\nvar output = f(3, 2); // output = 11\r\n```\r\n\r\nWe can see the difference by comparing the performance between the two:\r\n\r\n```csharp\r\nvar watch = System.Diagnostics.Stopwatch.StartNew();\r\n\r\nfor (int i = 0; i \u003c 1000000; i++)\r\n    function.Evaluate(3, 2);\r\n\r\nConsole.WriteLine($\"interpreted function time: {watch.ElapsedMilliseconds}ms\");\r\nwatch.Restart();\r\n\r\nfunction.Compile();\r\n\r\nConsole.WriteLine($\"compilation time: {watch.ElapsedMilliseconds}ms\");\r\nwatch.Restart();\r\n\r\nfor (int i = 0; i \u003c 1000000; i++)\r\n    function.Evaluate(3, 2);\r\n\r\nConsole.WriteLine($\"compiled function time: {watch.ElapsedMilliseconds}ms\");\r\n```\r\n\r\n```text\r\ninterpreted function time: 4601ms\r\ncompilation time: 4ms\r\ncompiled function time: 2ms\r\n```\r\n\r\n\r\n\u003ca name=\"searching-for-inputs\"\u003e\u003c/a\u003e\r\n## Searching for inputs\r\n\r\nZen can find function inputs that lead to some (un)desirable outcome. For example, we can find an `(x, y)` input pair such that `x` is less than zero and the output of the function is `11`:\r\n\r\n```csharp\r\nvar input = function.Find((x, y, result) =\u003e Zen.And(x \u003c= 0, result == 11)); \r\n// input.Value = (-1883171776, 1354548043)\r\n```\r\n\r\nThe type of the result in this case is `Option\u003c(int, int)\u003e`, which will have a pair of integer inputs that make the output 11 if such a pair exists. In this case the library will find `x = -1883171776` and `y = 1354548043`\r\n\r\nTo find multiple inputs, Zen supports an equivalent `FindAll` method, which returns an `IEnumerable` of inputs where each input in `inputs` will be unique so there are no duplicates.\r\n\r\n```csharp\r\nusing System.Linq;\r\n...\r\nvar inputs = function.FindAll((x, y, result) =\u003e Zen.And(x \u003c= 0, result == 11)).Take(5);\r\n```\r\n\r\n\r\n\u003ca name=\"computing-with-sets\"\u003e\u003c/a\u003e\r\n## Computing with sets\r\n\r\nWhile the `Find` function provides a way to find a single input to a function, Zen also provides an additional API for reasoning about sets of inputs and outputs to functions. It does this through a `StateSetTransformer` API. A transformer is created by calling the `Transformer()` method on a `ZenFunction` (or by calling `Zen.Transformer(...)`):\r\n\r\n```csharp\r\nvar f = new ZenFunction\u003cuint, uint\u003e(i =\u003e i + 1);\r\nStateSetTransformer\u003cuint, uint\u003e t = f.Transformer();\r\n```\r\n\r\nTransformers allow for manipulating (potentially huge) sets of objects efficient. For example, we can get the set of all input `uint` values where adding one will result in an output `y` that is no more than 10 thousand:\r\n\r\n```csharp\r\nStateSet\u003cuint\u003e inputSet = t.InputSet((x, y) =\u003e y \u003c= 10000);\r\n```\r\n\r\nThis set will include all the values `0 - 9999` as well as `uint.MaxValue` due to wrapping. Transformers can also manpulate sets by propagating them forward or backwards: \r\n\r\n```csharp\r\nStateSet\u003cuint\u003e outputSet = t.TransformForward(inputSet);\r\n```\r\n\r\nFinally, `StateSet` objects can also be intersected, unioned, and negated. We can pull an example element out of a set as follows (if one exists):\r\n\r\n```csharp\r\nOption\u003cuint\u003e example = inputSet.Element(); // example.Value = 0\r\n```\r\n\r\nInternally, transformers leverage [binary decision diagrams](https://github.com/microsoft/DecisionDiagrams) to represent, possibly very large, sets of objects efficiently.\r\n\r\n\r\n\u003ca name=\"generating-test-inputs\"\u003e\u003c/a\u003e\r\n## Generating test inputs\r\n\r\nZen can automatically generate test inputs for a given model by finding inputs that will lead to different execution paths. For instance, consider an insertion sort implementation. We can ask Zen to generate test inputs for the function that can then be used, for instance to test other sorting algorithms:\r\n\r\n```csharp\r\nvar f = new ZenFunction\u003cPair\u003cint, int\u003e, int\u003e(pair =\u003e Zen.If\u003cint\u003e(pair.Item1() \u003c pair.Item2(), 1, 2));\r\n\r\nforeach (var input in f.GenerateInputs())\r\n{\r\n    Console.WriteLine($\"input: {input}\");\r\n}\r\n```\r\n\r\nIn this case, we get the following output:\r\n\r\n```text\r\ninput: (0, 0)\r\ninput: (0, 1)\r\n```\r\n\r\nThe test generation approach uses [symbolic execution](https://en.wikipedia.org/wiki/Symbolic_execution) to enumerate program paths and solve constraints on inputs that lead down each path. Each `Zen.If` expression is treated as a program branch point (note: you can set the setting `Settings.PreserveBranches = true` to prevent Zen from simplifying formulas involving `If` by default if you want to preserve the expression structure.).\r\n\r\n\u003ca name=\"optimization\"\u003e\u003c/a\u003e\r\n## Optimization\r\n\r\nZen supports optimization of objective functions subject to constraints. The API is similar to that for `Solve`, but requires a maximization or minimization objective. The solver will find the maximal satisfying assignment to the variables.\r\n\r\n```csharp\r\nvar a = Zen.Symbolic\u003cReal\u003e();\r\nvar b = Zen.Symbolic\u003cReal\u003e();\r\nvar constraints = Zen.And(a \u003c= (Real)10, b \u003c= (Real)10, a + (Real)4 \u003c= b);\r\nvar solution = Zen.Maximize(objective: a + b, subjectTo: constraints); // a = 6, b = 10\r\n```\r\n\r\n\r\n\u003ca name=\"supported-data-types\"\u003e\u003c/a\u003e\r\n# Supported data types\r\n\r\nZen currently supports a subset of .NET types and also introduces some of its own data types summarized below.\r\n\r\n| .NET Type   | Description          | Supported by Z3 backend | Supported by BDD backend | Supported by `StateSetTransformers`\r\n| ------ | -------------------- | ----------------------- | ------------------------ | ------------|\r\n| `bool`   | {true, false}        | :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `byte`   | 8-bit value          | :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `char`   | 16-bit UTF-16 character   | :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `short`  | 16-bit signed value  | :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `ushort` | 16-bit unsigned value| :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `int`    | 32-bit signed value  | :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `uint`   | 32-bit unsigned value| :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `long`   | 64-bit signed value  | :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `ulong`  | 64-bit unsigned value| :heavy_check_mark:      | :heavy_check_mark:       | :heavy_check_mark: |\r\n| `Int\u003c_N\u003e` | N-bit signed value| :heavy_check_mark:      | :heavy_check_mark:  | :heavy_check_mark: |\r\n| `UInt\u003c_N\u003e` | N-bit unsigned value| :heavy_check_mark: | :heavy_check_mark:  | :heavy_check_mark: |\r\n| `Option\u003cT\u003e`    | an optional/nullable value of type `T` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:  |\r\n| `Pair\u003cT1, ...\u003e`  | pairs of different values | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:  |\r\n| `class`, `struct` | classes and structs with public fields and/or properties | :heavy_check_mark: | :heavy_check_mark:  | :heavy_check_mark:  |\r\n| `FSeq\u003cT\u003e`       | finite length sequence of elements of type `T` | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `FSet\u003cT\u003e`       | finite size set of elements of type `T` | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `FString` | finite length string | :heavy_check_mark: | :heavy_minus_sign:  | :heavy_minus_sign:  |\r\n| `BigInteger` | arbitrary length integer| :heavy_check_mark:           | :heavy_minus_sign:                 | :heavy_minus_sign:  |\r\n| `Real` | arbitrary precision rational number | :heavy_check_mark:           | :heavy_minus_sign:                 | :heavy_minus_sign:  |\r\n| `Map\u003cT1, T2\u003e` | arbitrary size maps of keys and values of type `T1` and `T2`. Note that `T1` and `T2` can not use finite sequences | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `Set\u003cT\u003e` | arbitrary size sets of values of type `T`. Same restrictions as with `Map\u003cT1, T2\u003e` | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `CMap\u003cT1, T2\u003e` | maps of constant keys of type `T1` to values of type `T2`. | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `CSet\u003cT\u003e` | sets of constants of type `T`. | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `Array\u003cT, _N\u003e` | Fixed size arrays of values of type `T`. | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `Seq\u003cT\u003e` | arbitrary size sequences of values of type `T`. Same restrictions as with `Set\u003cT\u003e`. Note that SMT solvers use heuristics to solve for sequences and are incomplete. | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n| `string` | arbitrary size strings. Implemented as `Seq\u003cchar\u003e` | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign:  |\r\n\r\n\r\n\u003ca name=\"primitive-types\"\u003e\u003c/a\u003e\r\n## Primitive types\r\n\r\nZen supports the primitive types `bool, byte, char, short, ushort, int, uint, long, ulong`. All primitive types support (in)equality and integer types support integer arithmetic operations. As an example:\r\n\r\n```csharp\r\nvar x = Symbolic\u003cint\u003e();\r\nvar y = Symbolic\u003cint\u003e();\r\nvar c1 = (~x \u0026 y) == 1;\r\nvar c2 = And(x + y \u003e 0, x + y \u003c 100);\r\nvar solution = And(c1, c2).Solve(); // x = -20, y = 105\r\n```\r\n\r\n\u003ca name=\"integer-types\"\u003e\u003c/a\u003e\r\n## Integer types\r\n\r\nAside from primitive types, Zen also supports the `BigInteger` type found in `System.Numerics` for reasoning about ubounded integers as well as other types of integers with fixed, but non-standard bit width (for instance a 7-bit integer). Out of the box, Zen provides the types `Int\u003c_N\u003e` and `UInt\u003c_N\u003e` for `N`=1, 2, 3, ..., 99, 100, 128, 256, 512 ,1024. You can also create a custom integer size by simply declaring a new struct:\r\n\r\n```csharp\r\npublic struct _101 { }\r\n```\r\n\r\n\u003ca name=\"options-and-tuples\"\u003e\u003c/a\u003e\r\n## Options, Tuples\r\n\r\nZen offers `Pair\u003cT1, T2, ...\u003e`, types as a lightweight alternative to classes. By default all values are assumed to be non-null by Zen. For nullable values, it provides an `Option\u003cT\u003e` type.\r\n\r\n```csharp\r\nvar b = Symbolic\u003cOption\u003cbyte\u003e\u003e();\r\nvar p = Symbolic\u003cPair\u003cint, int\u003e\u003e\u003e();\r\nvar solution = And(b.IsNone(), p.Item1() == 3).Solve(); // b = None, p = (3, 0)\r\n```\r\n\r\n\u003ca name=\"real-values\"\u003e\u003c/a\u003e\r\n## Real Values\r\n\r\nZen supports arbitrary precision rational numbers through the `Real` type.\r\n\r\n```csharp\r\nvar c = new Real(3, 2); // the fraction 3/2 or equivalently 1.5 \r\nvar x = Symbolic\u003cReal\u003e();\r\nvar y = Symbolic\u003cReal\u003e();\r\nvar solution = (2 * x + 3 * y == c).Solve(); // x = 1/2, y = 1/6\r\n```\r\n\r\n\u003ca name=\"finite-sequences-bags-maps\"\u003e\u003c/a\u003e\r\n## Finite Sequences, Bags, Maps\r\n\r\nZen supports several high-level data types that are finite (bounded) in size (the default size is 5 but can be changed). These include:\r\n\r\n- `FSeq\u003cT\u003e` for reasoning about variable length sequences of values where the order is important.\r\n- `FSet\u003cT\u003e` represents finite sets.\r\n\r\nOne can implement complex functionality over `FSeq\u003cT\u003e` types by combining the elements of the sequence. For instance, we can sum the elements of a sequence:\r\n\r\n```csharp\r\npublic Zen\u003cint\u003e Sum\u003cT\u003e(Zen\u003cFSeq\u003cint\u003e\u003e seq)\r\n{\r\n    return seq.Fold(Zen.Constant(0), (x, y) =\u003e x + y);\r\n}\r\n```\r\n\r\n\r\n\u003ca name=\"unbounded-sets-maps\"\u003e\u003c/a\u003e\r\n## Unbounded Sets and Maps\r\n\r\nZen supports `Set\u003cT\u003e` and `Map\u003cT1, T2\u003e` data types that do not restrict the size of the set/map. This type only works with the Z3 backend and requires that `T`, `T1` and `T2` not contain any finitized types (`FSeq`, `FString`, or `FSet`). Primitive types (bool, integers, string, BigInteger), classes/structs are allowed.\r\n\r\n```csharp\r\nvar s  = Symbolic\u003cstring\u003e();\r\nvar s1 = Symbolic\u003cSet\u003cstring\u003e\u003e();\r\nvar s2 = Symbolic\u003cSet\u003cstring\u003e\u003e();\r\nvar s3 = Symbolic\u003cSet\u003cstring\u003e\u003e();\r\nvar s4 = Symbolic\u003cSet\u003cstring\u003e\u003e();\r\n\r\nvar c1 = s1.Contains(\"a\");\r\nvar c2 = s1.Intersect(s2).Contains(\"b\");\r\nvar c3 = Implies(s == \"c\", s3.Add(s) == s2);\r\nvar c4 = s4 == s1.Union(s2);\r\nvar solution = And(c1, c2, c3, c4).Solve(); // s = \"a\", s1 = {b, a}, s2 = {b}, s3 = {}, s4 = {b, a}\r\n```\r\n\r\n\u003ca name=\"constant-sets-maps\"\u003e\u003c/a\u003e\r\n## Constant Sets and Maps\r\n\r\nArbitrary sets and maps described above are compiled to the SMT solver theory of Arrays. While this theory is quite general, it has known performance limitations. As a lightweight alternative, Zen provides the `CMap\u003cT1, T2\u003e` and `CSet\u003cT\u003e` classes that offer similar APIs but with the restriction that any map keys or set elements must be C# constant values and not Zen expressions. Zen will compile these sets and maps by creating fresh variables for all possible constants used by the user for these types.\r\n\r\nConstant maps are useful for managing a finite number of unknown variables that should be indexed to some data (e.g., a symbolic boolean variable for every edge in a C# graph), and may have better performance in many cases.\r\n\r\n`CMap\u003cT1, T2\u003e` represents a total map from keys of type `T1` to values of type `T2`. When a key is not explicitly added to the map, the resulting value will be the Zen default value for the type `T2` (e.g., `0` for integers, `false` for booleans). `CSet\u003cT\u003e` is simply implemented as a `CMap\u003cT, bool\u003e` that says for each key, if the element is in the set. Any example use is shown below:\r\n\r\n\r\n```csharp\r\nvar x = Symbolic\u003cint\u003e();\r\nvar m1 = Symbolic\u003cCMap\u003cstring, int\u003e\u003e();\r\nvar m2 = Symbolic\u003cCMap\u003cstring, int\u003e\u003e();\r\n\r\nvar c1 = m1.Get(\"a\") == Zen.If(x \u003c 10, x + 1, x + 2);\r\nvar c2 = m2 == m1.Set(\"b\", x);\r\nvar solution = And(c1, c2).Solve(); // x = 0, m1 = m2 = {\"a\" =\u003e 1, _ =\u003e 0}\r\n```\r\n\r\nConstant maps and sets have several limitations:\r\n* Inequality may not always give the expected result, as the constant maps do not have a canonical representation.\r\n* They can not be used as values in the `Map`, `Set`, or `Seq` types. This restriction may be relaxed in the future.\r\n\r\n\u003ca name=\"arrays\"\u003e\u003c/a\u003e\r\n## Fixed Length Arrays\r\n\r\nZen can model fixed-length arrays of symbolic values using the `Array\u003cT, TSize\u003e` class. As an example:\r\n\r\n```csharp\r\nvar a = Zen.Symbolic\u003cArray\u003cint, _10\u003e\u003e();           // create a symbolic array of size 10\r\nZen\u003cint\u003e[] elements = a.ToArray();                 // get the symbolic elements of the array\r\nvar solution = Zen.And(\r\n    elements.Aggregate(Zen.Plus) == 100,\r\n    a.All(x =\u003e Zen.And(x \u003e= 1, x \u003c= 20))).Solve(); // a = [8,6,13,16,14,15,5,13,5,5]\r\n```\r\n\r\nThe type parameter `TSize` specifies the size of the array. The types `_1` through `_100` are predefined in the library. To add a custom size, you can create a new struct following this naming convention:\r\n\r\n```csharp\r\nstruct _150 { }\r\n```\r\n\r\n\r\n\u003ca name=\"strings-and-sequences\"\u003e\u003c/a\u003e\r\n## Sequences, Strings, and Regular Expressions\r\n\r\nZen has a `Seq\u003cT\u003e` type to represent arbitrarily large sequences of elements of type `T`. As there is no complete decision procedure for sequences in constraint solvers, queries for sequences may not always terminate, and you may need to use a timeout. If this is not acceptable, you can always use `FSeq` or `FString` instead, which will model a finite sequence up to a given size. Sequences also support matching against regular expressions. As an example:\r\n\r\n```csharp\r\nRegex\u003cint\u003e r = Regex.Star(Regex.Char(1)); // zero or more 1s in a Seq\u003cint\u003e\r\n\r\nvar s1 = Symbolic\u003cSeq\u003cint\u003e\u003e();\r\nvar s2 = Symbolic\u003cSeq\u003cint\u003e\u003e();\r\n\r\nvar c1 = s1.MatchesRegex(r);\r\nvar c2 = s1 != Seq.Empty\u003cint\u003e();\r\nvar c3 = Not(s2.MatchesRegex(r));\r\nvar c4 = s1.Length() == s2.Length();\r\nvar solution = And(c1, c2, c3, c4).Solve(); // s1 = [1], s2 = [0]\r\n```\r\n\r\nZen supports the `string` type for reasoning about unbounded strings (the `string` type is implemented as a `Seq\u003cchar\u003e`). Strings also support matching regular expressions. Zen supports a limited subset of regex constructs currently - it supports anchors like `$` and `^` but not any other metacharacters like `\\w,\\s,\\d,\\D,\\b` or backreferences `\\1`. As an example:\r\n\r\n```csharp\r\nRegex\u003cchar\u003e r1 = Regex.Parse(\"[0-9a-z]+\");\r\nRegex\u003cchar\u003e r2 = Regex.Parse(\"(0.)*\");\r\n\r\nvar s = Symbolic\u003cstring\u003e();\r\n\r\nvar c1 = s.MatchesRegex(Regex.Intersect(r1, r2));\r\nvar c2 = s.Contains(\"a0b0c\");\r\nvar c3 = s.Length() == new BigInteger(10);\r\nvar solution = And(c1, c2, c3).Solve(); // s = \"020z0a0b0c\"\r\n```\r\n\r\n\u003ca name=\"custom-classes-and-structs\"\u003e\u003c/a\u003e\r\n## Custom classes and structs\r\n\r\nZen supports custom `class` and `struct` types with some limitations. It will attempt to model all public fields and properties. For these types to work, either (1) the class/struct must also have a default constructor and all properties must be allowed to be set, or (2) there must be a constructor with matching parameter names and types for all the public fields. For example, the following are examples that are and are not allowed:\r\n\r\n```csharp\r\n// this will work because the fields are public\r\npublic class Point \r\n{ \r\n    public int X;\r\n    public int Y;\r\n}\r\n\r\n// this will work because the properties are public and can be set.\r\npublic class Point \r\n{ \r\n    public int X { get; set; }\r\n    public int Y { get; set; }\r\n}\r\n\r\n// this will NOT work because X can not be set.\r\npublic class Point \r\n{ \r\n    public int X { get; }\r\n    public int Y { get; set; }\r\n}\r\n\r\n// this will work as well since there is a constructor with the same parameter names.\r\n// note that _z will not be modeled by Zen.\r\npublic class Point \r\n{ \r\n    public int X { get; }\r\n    public int Y { get; set; }\r\n    private int _z;\r\n\r\n    public Point(int x, int y) \r\n    {\r\n        this.X = x;\r\n        this.Y = y;\r\n    }\r\n}\r\n\r\n```\r\n\r\n\u003ca name=\"enums\"\u003e\u003c/a\u003e\r\n## Enumerated values\r\n\r\nEnums in C# are just structs that wrap some backing type. Zen will model enums like any other struct. For example, Zen will model the following enum as a byte:\r\n\r\n```csharp\r\npublic enum Origin : byte\r\n{\r\n    Egp,\r\n    Igp,\r\n    Incomplete,\r\n}\r\n```\r\n\r\nBy default, Zen does not constraint an enum value to only be one of the enumerated values - it can be any value allowed by the backing type (any value between 0 and 255 in this example instead of just the 3 listed). If you want to add a constraint to ensure the value is only one of those enumerated by the user, you write a function like the following to test if a value is one of those expected:\r\n\r\n```csharp\r\npublic Zen\u003cbool\u003e IsValidOrigin(Zen\u003cOrigin\u003e origin)\r\n{\r\n    return Zen.Or(Enum.GetValues\u003cOrigin\u003e().Select(x =\u003e origin == x));\r\n}\r\n```\r\n\r\n\r\n\u003ca name=\"zen-attributes\"\u003e\u003c/a\u003e\r\n# Zen Attributes\r\n\r\nZen provides two attributes to simplify the creation and manipulation of symbolic objects. The first attribute `[ZenObject]` can be applied to classes or structs. It uses C# source generators to generate Get and With methods for all public fields and properties.\r\n\r\n```csharp\r\n[ZenObject]\r\npublic class Point \r\n{ \r\n    public int X { get; set; }\r\n    public int Y { get; set; }\r\n\r\n    public static Zen\u003cPoint\u003e Add(Zen\u003cPoint\u003e p1, Zen\u003cPoint\u003e p2)\r\n    {\r\n        return p1.WithX(p1.GetX() + p2.GetX()).WithY(p1.GetY() + p2.GetY());\r\n    }\r\n}\r\n```\r\n\r\nNote that this requires C# 9.0 and .NET 6 or later to work. In addition, you must add the ZenLib.Generators nuget package to enable code generation. The other attribute supported is the `ZenSize` attribute, which controls the size of a generated field in an object. For example, to fix the size of a `FSeq` to 10:\r\n\r\n```csharp\r\npublic class Person\r\n{\r\n    [ZenSize(depth: 10)]\r\n    public FSeq\u003cstring\u003e Contacts { get; set; }\r\n}\r\n```\r\n\r\n\r\n\u003ca name=\"solver-backends\"\u003e\u003c/a\u003e\r\n# Solver Backends\r\n\r\nZen currently supports two solvers, one based on the [Z3](https://github.com/Z3Prover/z3) SMT solver and another based on [binary decision diagrams](https://github.com/microsoft/DecisionDiagrams) (BDDs). The `Find` and `Zen.Solve` APIs provide an option to select one of the two backends and will default to Z3 if left unspecified. The `StateSetTransformer` API uses the BDD backend. The BDD backend has the limitation that it can only reason about bounded-size objects. This means that it can not reason about values with type `BigInteger` or `string` and will throw an exception. Similarly, these types along with `FSeq\u003cT\u003e`, `FSet\u003cT\u003e`, and `Map\u003cT1, T2\u003e` can not be used with transformers.\r\n\r\n\u003ca name=\"solver-timeouts\"\u003e\u003c/a\u003e\r\n# Solver Timeouts\r\n\r\nZen supports terminating a call to the solver via the `Solve`, `Maximize`, `Minimize`, and `Find` methods for the Z3 backend. If the solver times out, it will raise a `ZenSolverTimeoutException`. For example, you can try to find a solution within 100 milliseconds with the following:\r\n\r\n```csharp\r\nvar solverConfig = new ZenLib.Solver.SolverConfig\r\n{\r\n    SolverType = SolverType.Z3,\r\n    SolverTimeout = TimeSpan.FromMilliseconds(100),\r\n};\r\n\r\ntry\r\n{\r\n    var solution = Zen.And(constraints).Solve(config: solverConfig);\r\n    ...\r\n}\r\ncatch (ZenSolverTimeoutException)\r\n{\r\n    Console.WriteLine($\"a timeout occurred.\");\r\n}\r\n```\r\n\r\n\u003ca name=\"example-network-acls\"\u003e\u003c/a\u003e\r\n# Example: Network ACLs\r\n\r\nAs a more complete example, the following shows how to use Zen to encode and then verify a simplified network access control list that allows or blocks packets. ACLs generally consist of an ordered collection of match-action rules that apply in sequence with the first applicable rule determining the fate of the packet. We can model an ACL with Zen:\r\n\r\n```csharp\r\n// define a class to model Packets using public properties\r\n[ZenObject]\r\npublic class Packet\r\n{\r\n    // packet destination ip\r\n    public uint DstIp { get; set; } \r\n    // packet source ip\r\n    public uint SrcIp { get; set; }\r\n}\r\n\r\n// class representing an ACL with a list of prioritized rules.\r\npublic class Acl\r\n{\r\n    public string Name { get; set; }\r\n    public AclLine[] Lines { get; set; }\r\n\r\n    public Zen\u003cbool\u003e Allowed(Zen\u003cPacket\u003e packet)\r\n    {\r\n        return Allowed(packet, 0);\r\n    }\r\n\r\n    // compute whether a packet is allowed by the ACL recursively\r\n    private Zen\u003cbool\u003e Allowed(Zen\u003cPacket\u003e packet, int lineNumber)\r\n    {\r\n        if (lineNumber \u003e= this.Lines.Length) \r\n        {\r\n            return false; // Zen implicitly converts false to Zen\u003cbool\u003e\r\n        }\r\n\r\n        var line = this.Lines[lineNumber];\r\n\r\n        // if the current line matches, then return the action, otherwise continue to the next line\r\n        return If(line.Matches(packet), line.Action, this.Allowed(packet, lineNumber + 1));\r\n    }\r\n}\r\n\r\n// An ACL line that matches a packet.\r\npublic class AclLine\r\n{\r\n    public bool Action { get; set; }\r\n    public uint DstIpLow { get; set; }\r\n    public uint DstIpHigh { get; set; }\r\n    public uint SrcIpLow { get; set; }\r\n    public uint SrcIpHigh { get; set; }\r\n\r\n    // a packet matches a line if it falls within the specified ranges.\r\n    public Zen\u003cbool\u003e Matches(Zen\u003cPacket\u003e packet)\r\n    {\r\n        return And(\r\n            packet.GetDstIp() \u003e= this.DstIpLow,\r\n            packet.GetDstIp() \u003c= this.DstIpHigh,\r\n            packet.GetSrcIp() \u003e= this.SrcIpLow,\r\n            packet.GetSrcIp() \u003c= this.SrcIpHigh);\r\n    }\r\n}\r\n```\r\n\r\n\u003ca name=\"implementation\"\u003e\u003c/a\u003e\r\n# Implementation Details\r\nZen builds an abstract syntax tree (AST) for a given user function and then leverages C#'s reflection capabilities to interpret, compile, and symbolically evaluate the AST.\r\n\r\n\u003ca name=\"contributing\"\u003e\u003c/a\u003e\r\n# Contributing\r\n\r\nThis project welcomes contributions and suggestions.  Most contributions require you to agree to a\r\nContributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us\r\nthe rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.\r\n\r\nWhen you submit a pull request, a CLA bot will automatically determine whether you need to provide\r\na CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions\r\nprovided by the bot. You will only need to do this once across all repos using our CLA.\r\n\r\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).\r\nFor more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or\r\ncontact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrosoft%2Fzen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicrosoft%2Fzen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrosoft%2Fzen/lists"}