# Goal & Constraints

Optimization goals and constraints are defined using a YAML manifest with the following structure:

```yaml
goal:
  objective: "minimize"
  function:
    formula: "jvm1.response_time + jvm2.response_time"
  constraints:
    absolute:
      - name: heap_used
        formula: jvm1.heap_used <= 3221225472
    relativeToBaseline:
      - name: memory_used
        formula: jvm1.memory_used <= 80%
```

where:

| Field         | Type            | Value restriction                                                     | Is Required | Default value | Description                                                                                                                                                                                                       |
| ------------- | --------------- | --------------------------------------------------------------------- | ----------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `objective`   | String          | `minimize` `maximize`                                                 | Yes         |               | How Akamas should evaluate the goodness of a generated configuration: if it should consider good a configuration generated that maximizes `function`, or a configuration that minimizes it.                       |
| `function`    | Object          | It should have a structure like the one described in Goal function    | Yes         |               | The specification of the function to be evaluated to assess the goodness of a configuration generated by Akamas. This function is a function of the metrics of the different Components of the System under test. |
| `constraints` | List of objects | It should have a structure like the one described in Goal constraints | No          |               | A list of constraints on aggregated metrics of the Components of the System under test for which a generated configuration should not be considered valid.                                                        |

### Function <a href="#goal-function" id="goal-function"></a>

The `function` field of the Goal of a Study details the characteristics of the function Akamas should minimize or maximize to reach the desired performance objective.

The `function` field has the following structure:

```yaml
function:
  formula: "jvm1.response_time / sqrt(x:max)"
  variables:
    x:
      metric: "throughput"
      labels:
        componentName: "jvm2"
```

Where:

| Field       | Type   | Value restrictions | Is required | Default value | Description                                                                                      |
| ----------- | ------ | ------------------ | ----------- | ------------- | ------------------------------------------------------------------------------------------------ |
| `formula`   | String | See formula        | Yes         |               | The mathematical expression of what to minimize or maximize to reach the objective of the Study. |
| `variables` | Object | See below          | No          |               | The specification of additional variables present in the `formula`.                              |

#### Formula <a href="#formula" id="formula"></a>

The `formula` field represents the mathematical expression of the performance objective for the Study and contains variables and operators with the following characteristics:

* Valid operators are: `+`, `-`, `*`, `/`, `^`, `sqrt(variable)`, `log(variable)`, `max(variable1, variable2)`, and `min(variable1, variable2)`
* Valid variables are in the form:
  * \<component\_name>.\<metric\_name>, which correspond directly to metrics of Components of the System under test
  * \<variable\_name>, which should match variables specified in the `variables` field

Each metric that is directly or indirectly part of the formula of the function of the Goal is aggregated by default by average; more specifically, Akamas computes the average of each metric within the time window specified by the [windowing strategy](https://docs.akamas.io/akamas-docs/3.6/reference/construct-templates/study-template/windowing-strategy) of the Study. Variables in the formula can be expanded with an aggregation in the form of `<variable>:<aggreggation>`. A list of available aggregations is available in the section [Aggregations](#aggregations).

#### Variables <a href="#variables" id="variables"></a>

The `variables` field contains the specification of additional variables present in the formula, variables that can offer more flexibility compared to directly specifying each metric of each Component in the `formula`.

Notice: each subfield of variables specifies a variable with its characteristics, the name of the subfield is the name of the variable.

The variable subfield has the following structure:

| Field         | Type                     | Value restrictions                                                                    | Is required | Default value | Description                                                                                                                                                                                                               |
| ------------- | ------------------------ | ------------------------------------------------------------------------------------- | ----------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metric`      | String                   | should match the name of a metric defined for the Components of the System under test | Yes         |               | The name of the metric of the Components of the System under test that maps to the variable.                                                                                                                              |
| `labels`      | A set of key-value pairs |                                                                                       | No          |               | A set of filters based on the values of the labels that are attached to the different data points of the `metric`. One of these labels is *componentName*, which contains the name of the Component the metric refers to. |
| `aggregation` | String                   | `MAX` `MIN` `AVG`                                                                     | No          | `AVG`         | The strategy through which data points of the `metric` should be aggregated within the window produced by the application of the selected windowing strategy. By default, an average is taken.                            |

It is possible to use the notation \<component\_name>.\<metric\_name> in the `metric` field to automatically filter the metric’s data point by that component name is applied.

## Constraints <a href="#constraints" id="constraints"></a>

The `constraints` field specifies constraints on the metrics of the system under test. For a configuration to be valid for the defined goal, such constraints must be satisfied. Constraints can be defined as `absolute` or `relativeToBaseline`.

Each constraint has the form of:

*`mathematical_operation`**`comparison_operator`**`value_to_compare`*

where valid mathematical operations include:

* `+` `-` `*` `/` `^`
* `min` `max`
* `sqrt` `log` (log is a natural logarithm)

valid comparison operators include:

* `>` `<` `<=` `>=`
* `==` `!=` (equality, inequality)

and valid values to compare include:

* absolute values (e.g, 104343)
* percentage values relative to the baseline (e.g, 20%)

As an example, you could define an absolute constraint with the following snippet:

```yaml
goal:
  objective: "minimize"
  function:
    formula: "jvm.response_time"
  constraints:
    absolute:
      - name: heap_used
        formula: jvm.heap_used <= 3221225472
```

Relative constraints can be defined by adding other constraints under the `relativeToBaseline` section. In the example below, for the configuration to be considered valid, it's required that the metric `jvm.memory_used` does not exceed by 80% the value measured in the baseline.

```yaml
goal:
  objective: "minimize"
  function:
    formula: "jvm.response_time"
  constraints:
    absolute:
      - name: heap_used
        formula: jvm.heap_used <= 3221225472
    relativeToBaseline:
      - name: memory_used
        formula: jvm.memory_used <= 80%
```

### Aggregations

Variables used in the study formula specification and in the constraints definition can include an aggregation. The following aggregations are available: `avg`, `min`, `max`, `sum`, `p90`, `p95`, `p99`.

### Examples <a href="#examples" id="examples"></a>

The following example refers to a study whose goal is to optimize the throughput of a Java service (*jpetstore*), that is to maximize the throughput (measured as *elements\_per\_second*) while keeping errors (*error\_rate*) and latency (*avg\_duration*, *max\_duration*) under control (absolute values):

```yaml
goal:
    objective: "maximize"
    function:
      formula: "jpetstore.elements_per_second"
    constraints:
      absolute:
        - name: elements_per_second
          formula: "jpetstore.elements_per_second > 55"
        - name: max_duration
          formula: "jpetstore.max_duration < 800"
        - name: avg_duration
          formula: "jpetstore.avg_duration < 70"
        - name: error_rate
          formula: "jpetstore.error_rate < 0.01"
```

The following example refers to a study whose goal is to optimize the memory consumption of Docker containers in a microservices application, that is to minimize the average memory consumption of Docker containers within the application of *appId*="app1" by observing memory limits, also normalizing by the maximum duration of a benchmark (containers\_benchmark\_duration).

```yaml
goal:
  objective: "minimize"
  function:
    formula: "containers_memory_limit/containers_benchmark_duration:max"
    variables:
      containers_memory_limit:
        metric: "memory_limit"
        labels:
          appId: "app1"
      containers_benchmark_duration:
        metric: "benchmark_duration"
        labels:
          appId: "app1"
```
