Skip to content
LIBRARY
Examples.Binary.IntegerControlMPCExample.md

Examples.Binary.IntegerControlMPCExample ​

Regulation of a double integrator to the origin with the control restricted to the integer values u ∈ {-1, 0, 1} — the Dyad version of the DyadControlSystems MINLP MPC tutorial (https://help.juliahub.com/dyad/DyadControlSystems.jl/stable/examples/minlp_mpc/). Three parallel closed loops around the same plant

Misplaced &

from the initial state [10, 0] compare real-valued control (loop 1), integer control enforced over the full horizon (loop 2), and integer control enforced over only the first two prediction steps (loop 3, Nc_binary = 2 — the tutorial's Nint). The plants are exact discrete models (DiscreteStateSpace) and the full state is fed to a LinearMPCOptimizer directly, the Dyad version of the tutorial's StateFeedback observer. The cost is the tutorial's: unit weight on both states, 0.1 u^2 on the control and ten times the state weight as terminal cost.

DAQP's binary controls take only the two values {umin, umax}, so the three-valued integer set is encoded with two binary inputs u = u1 - u2, u1, u2 ∈ {0, 1}: the integer-controlled plants take both inputs with input matrix [B, -B], and the control weight is the rank-one 0.1 (u1 - u2)^2 plus 1e-6 on the diagonal, which keeps the MIQP Hessian positive definite and makes (0, 0) the preferred encoding of u = 0.

The three state trajectories are nearly identical (the plant integrates, so it low-pass filters the control), while the control signals differ markedly: smooth for loop 1, a {-1, 0, 1} staircase for loops 2 and 3. Loop 3 tracks loop 2 closely at a fraction of the computational cost — the branch-and-bound tree grows exponentially in the number of binary steps, and two steps suffice because control decisions far into the future hardly affect the first move. examples/minlp_mpc.jl simulates this model and reproduces the tutorial's comparison plot.

Usage ​

MPCComponents.Examples.Binary.IntegerControlMPCExample()

Parameters: ​

NameDescriptionUnitsDefault value
ctrl_realReal-valued controller, u ∈ [-1, 1]–build_linea...king=false)
ctrl_binaryInteger controller, u1 - u2 ∈ {-1, 0, 1} over the full horizon–build_linea...king=false)
ctrl_binary2Integer controller, binary only over the first two steps, relaxed to [0, 1] after–build_linea...king=false)

Variables ​

NameDescriptionUnits
p1Position, real-valued control–
v1Velocity, real-valued control–
u1Control signal, real-valued–
p2Position, full binary horizon–
v2Velocity, full binary horizon–
u2Control signal u1 - u2, full binary horizon–
p3Position, binary horizon 2–
v3Velocity, binary horizon 2–
u3Control signal u1 - u2, binary horizon 2–

Behavior ​

Behavior of this component cannot be rendered because it includes path variables.

Source ​

dyad
"""
Regulation of a double integrator to the origin with the control restricted to the integer
values `u ∈ {-1, 0, 1}` — the Dyad version of the DyadControlSystems MINLP MPC tutorial
(https://help.juliahub.com/dyad/DyadControlSystems.jl/stable/examples/minlp_mpc/). Three
parallel closed loops around the same plant

```math
\\begin{aligned}
p^+ &= p + T_s v \\\\
v^+ &= v + T_s u
\\end{aligned}
```

from the initial state `[10, 0]` compare real-valued control (loop 1), integer control enforced
over the full horizon (loop 2), and integer control enforced over only the first two prediction
steps (loop 3, `Nc_binary = 2` — the tutorial's `Nint`). The plants are exact discrete models
(`DiscreteStateSpace`) and the full state is fed to a `LinearMPCOptimizer` directly, the Dyad
version of the tutorial's `StateFeedback` observer. The cost is the tutorial's:
unit weight on both states, `0.1 u^2` on the control and ten times the state weight as terminal
cost.

DAQP's binary controls take only the two values `{umin, umax}`, so the three-valued integer set
is encoded with two binary inputs `u = u1 - u2`, `u1, u2 ∈ {0, 1}`: the integer-controlled
plants take both inputs with input matrix `[B, -B]`, and the control weight is the rank-one
`0.1 (u1 - u2)^2` plus `1e-6` on the diagonal, which keeps the MIQP Hessian positive definite
and makes `(0, 0)` the preferred encoding of `u = 0`.

The three state trajectories are nearly identical (the plant integrates, so it low-pass filters
the control), while the control signals differ markedly: smooth for loop 1, a `{-1, 0, 1}`
staircase for loops 2 and 3. Loop 3 tracks loop 2 closely at a fraction of the computational
cost — the branch-and-bound tree grows exponentially in the number of binary steps, and two
steps suffice because control decisions far into the future hardly affect the first move.
`examples/minlp_mpc.jl` simulates this model and reproduces the tutorial's comparison plot.
"""
example component IntegerControlMPCExample
  clock1 = DiscreteComponents.PeriodicClock(dt = 0.1) {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 70, "y2": 170}}}
  }
  "Plant with real-valued control"
  plant1 = DiscreteComponents.DiscreteStateSpace(nx = 2, nu = 1, ny = 2, A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0], [0.1]], C = [[1.0, 0.0], [0.0, 1.0]], with_D = false, initialization = DiscreteComponents.InitialCondition.InitialStateArray(x0 = [10.0, 0.0])) {
    "Dyad": {"placement": {"diagram": {"x1": 340, "x2": 440, "y1": 40, "y2": 140}}}
  }
  "Real-valued MPC"
  mpc1 = MPCComponents.LinearMPCOptimizer(mpc = ctrl_real) {
    "Dyad": {"placement": {"diagram": {"x1": 180, "x2": 280, "y1": 40, "y2": 140}}}
  }
  "Continuous-time hold of the control; a model with no continuous part fails to initialize"
  zoh1 = DiscreteComponents.ZeroOrderHold() {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": -50, "y2": 50}}}
  }
  "Plant with integer control, u = u1 - u2"
  plant2 = DiscreteComponents.DiscreteStateSpace(nx = 2, nu = 2, ny = 2, A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], C = [[1.0, 0.0], [0.0, 1.0]], with_D = false, initialization = DiscreteComponents.InitialCondition.InitialStateArray(x0 = [10.0, 0.0])) {
    "Dyad": {"placement": {"diagram": {"x1": 340, "x2": 440, "y1": 340, "y2": 440}}}
  }
  "MPC with binary controls over the full horizon"
  mpc2 = MPCComponents.LinearMPCOptimizer(mpc = ctrl_binary) {
    "Dyad": {"placement": {"diagram": {"x1": 180, "x2": 280, "y1": 340, "y2": 440}}}
  }
  "Continuous-time hold of the control; a model with no continuous part fails to initialize"
  zoh2 = DiscreteComponents.ZeroOrderHold() {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 250, "y2": 350}}}
  }
  "Plant with integer control, u = u1 - u2"
  plant3 = DiscreteComponents.DiscreteStateSpace(nx = 2, nu = 2, ny = 2, A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], C = [[1.0, 0.0], [0.0, 1.0]], with_D = false, initialization = DiscreteComponents.InitialCondition.InitialStateArray(x0 = [10.0, 0.0])) {
    "Dyad": {"placement": {"diagram": {"x1": 340, "x2": 440, "y1": 600, "y2": 700}}}
  }
  "MPC with binary controls over the first two prediction steps only"
  mpc3 = MPCComponents.LinearMPCOptimizer(mpc = ctrl_binary2) {
    "Dyad": {"placement": {"diagram": {"x1": 180, "x2": 280, "y1": 600, "y2": 700}}}
  }
  "Continuous-time hold of the control; a model with no continuous part fails to initialize"
  zoh3 = DiscreteComponents.ZeroOrderHold() {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 510, "y2": 610}}}
  }
  periodicclock = DiscreteComponents.PeriodicClock(dt = 0.1) {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 370, "y2": 470}}}
  }
  periodicclock1 = DiscreteComponents.PeriodicClock(dt = 0.1) {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 630, "y2": 730}}}
  }
  "Real-valued controller, u ∈ [-1, 1]"
  structural parameter ctrl_real::MPCComponents.MPCRef = build_linear_mpc(A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0], [0.1]], Np = 10, Q1 = [1.0, 1.0], Q2 = [0.1], Qf = [10.0, 10.0], umin = [-1.0], umax = [1.0], reference_tracking = false)
  "Integer controller, u1 - u2 ∈ {-1, 0, 1} over the full horizon"
  structural parameter ctrl_binary::MPCComponents.MPCRef = build_linear_mpc(A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], Np = 10, Q1 = [1.0, 1.0], Q2 = [[0.100001, -0.1], [-0.1, 0.100001]], Qf = [10.0, 10.0], umin = [0.0, 0.0], umax = [1.0, 1.0], binary_controls = [1, 2], reference_tracking = false)
  "Integer controller, binary only over the first two steps, relaxed to [0, 1] after"
  structural parameter ctrl_binary2::MPCComponents.MPCRef = build_linear_mpc(A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], Np = 10, Q1 = [1.0, 1.0], Q2 = [[0.100001, -0.1], [-0.1, 0.100001]], Qf = [10.0, 10.0], umin = [0.0, 0.0], umax = [1.0, 1.0], binary_controls = [1, 2], Nc_binary = 2, reference_tracking = false)
  "Position, real-valued control"
  variable p1::Real
  "Velocity, real-valued control"
  variable v1::Real
  "Control signal, real-valued"
  variable u1::Real
  "Position, full binary horizon"
  variable p2::Real
  "Velocity, full binary horizon"
  variable v2::Real
  "Control signal u1 - u2, full binary horizon"
  variable u2::Real
  "Position, binary horizon 2"
  variable p3::Real
  "Velocity, binary horizon 2"
  variable v3::Real
  "Control signal u1 - u2, binary horizon 2"
  variable u3::Real
relations
  p1 = plant1.y[1]
  v1 = plant1.y[2]
  u1 = mpc1.u[1]
  p2 = plant2.y[1]
  v2 = plant2.y[2]
  u2 = mpc2.u[1] - mpc2.u[2]
  p3 = plant3.y[1]
  v3 = plant3.y[2]
  u3 = mpc3.u[1] - mpc3.u[2]
  connect(mpc1.u[1], zoh1.u, clock1.y) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [{"x": 310, "y": 113}, {"x": 310, "y": 0}], "E": 2},
        {"S": 2, "M": [], "E": 3}
      ],
      "path": {}
    }
  }
  connect(mpc2.u[1], zoh2.u, periodicclock.y) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [{"x": 310, "y": 413}, {"x": 310, "y": 300}], "E": 2},
        {"S": 2, "M": [], "E": 3}
      ],
      "path": {}
    }
  }
  connect(mpc3.u[1], zoh3.u, periodicclock1.y) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [{"x": 310, "y": 673}, {"x": 310, "y": 560}], "E": 2},
        {"S": 2, "M": [], "E": 3}
      ],
      "path": {}
    }
  }
  connect(plant1.y, mpc1.xhat) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 460, "y": 90},
            {"x": 460, "y": 180},
            {"x": 160, "y": 180},
            {"x": 160, "y": 90}
          ],
          "E": 2
        }
      ],
      "path": {}
    }
  }
  connect(plant2.y, mpc2.xhat) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 460, "y": 390},
            {"x": 460, "y": 470},
            {"x": 160, "y": 470},
            {"x": 160, "y": 390}
          ],
          "E": 2
        }
      ],
      "path": {}
    }
  }
  connect(mpc3.xhat, plant3.y) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 160, "y": 650},
            {"x": 160, "y": 730},
            {"x": 460, "y": 730},
            {"x": 460, "y": 650}
          ],
          "E": 2
        }
      ],
      "path": {}
    }
  }
  connect(mpc1.u, plant1.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 310, "y": 113}, {"x": 310, "y": 90}], "E": 2}],
      "path": {}
    }
  }
  connect(mpc2.u, plant2.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 310, "y": 413}, {"x": 310, "y": 390}], "E": 2}],
      "path": {}
    }
  }
  connect(mpc3.u, plant3.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 310, "y": 673}, {"x": 310, "y": 650}], "E": 2}],
      "path": {}
    }
  }
metadata {"Dyad": {"doc": {"behavior": false}}}
end
Flattened Source
dyad
"""
Regulation of a double integrator to the origin with the control restricted to the integer
values `u ∈ {-1, 0, 1}` — the Dyad version of the DyadControlSystems MINLP MPC tutorial
(https://help.juliahub.com/dyad/DyadControlSystems.jl/stable/examples/minlp_mpc/). Three
parallel closed loops around the same plant

```math
\\begin{aligned}
p^+ &= p + T_s v \\\\
v^+ &= v + T_s u
\\end{aligned}
```

from the initial state `[10, 0]` compare real-valued control (loop 1), integer control enforced
over the full horizon (loop 2), and integer control enforced over only the first two prediction
steps (loop 3, `Nc_binary = 2` — the tutorial's `Nint`). The plants are exact discrete models
(`DiscreteStateSpace`) and the full state is fed to a `LinearMPCOptimizer` directly, the Dyad
version of the tutorial's `StateFeedback` observer. The cost is the tutorial's:
unit weight on both states, `0.1 u^2` on the control and ten times the state weight as terminal
cost.

DAQP's binary controls take only the two values `{umin, umax}`, so the three-valued integer set
is encoded with two binary inputs `u = u1 - u2`, `u1, u2 ∈ {0, 1}`: the integer-controlled
plants take both inputs with input matrix `[B, -B]`, and the control weight is the rank-one
`0.1 (u1 - u2)^2` plus `1e-6` on the diagonal, which keeps the MIQP Hessian positive definite
and makes `(0, 0)` the preferred encoding of `u = 0`.

The three state trajectories are nearly identical (the plant integrates, so it low-pass filters
the control), while the control signals differ markedly: smooth for loop 1, a `{-1, 0, 1}`
staircase for loops 2 and 3. Loop 3 tracks loop 2 closely at a fraction of the computational
cost — the branch-and-bound tree grows exponentially in the number of binary steps, and two
steps suffice because control decisions far into the future hardly affect the first move.
`examples/minlp_mpc.jl` simulates this model and reproduces the tutorial's comparison plot.
"""
example component IntegerControlMPCExample
  clock1 = DiscreteComponents.PeriodicClock(dt = 0.1) {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 70, "y2": 170}}}
  }
  "Plant with real-valued control"
  plant1 = DiscreteComponents.DiscreteStateSpace(nx = 2, nu = 1, ny = 2, A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0], [0.1]], C = [[1.0, 0.0], [0.0, 1.0]], with_D = false, initialization = DiscreteComponents.InitialCondition.InitialStateArray(x0 = [10.0, 0.0])) {
    "Dyad": {"placement": {"diagram": {"x1": 340, "x2": 440, "y1": 40, "y2": 140}}}
  }
  "Real-valued MPC"
  mpc1 = MPCComponents.LinearMPCOptimizer(mpc = ctrl_real) {
    "Dyad": {"placement": {"diagram": {"x1": 180, "x2": 280, "y1": 40, "y2": 140}}}
  }
  "Continuous-time hold of the control; a model with no continuous part fails to initialize"
  zoh1 = DiscreteComponents.ZeroOrderHold() {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": -50, "y2": 50}}}
  }
  "Plant with integer control, u = u1 - u2"
  plant2 = DiscreteComponents.DiscreteStateSpace(nx = 2, nu = 2, ny = 2, A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], C = [[1.0, 0.0], [0.0, 1.0]], with_D = false, initialization = DiscreteComponents.InitialCondition.InitialStateArray(x0 = [10.0, 0.0])) {
    "Dyad": {"placement": {"diagram": {"x1": 340, "x2": 440, "y1": 340, "y2": 440}}}
  }
  "MPC with binary controls over the full horizon"
  mpc2 = MPCComponents.LinearMPCOptimizer(mpc = ctrl_binary) {
    "Dyad": {"placement": {"diagram": {"x1": 180, "x2": 280, "y1": 340, "y2": 440}}}
  }
  "Continuous-time hold of the control; a model with no continuous part fails to initialize"
  zoh2 = DiscreteComponents.ZeroOrderHold() {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 250, "y2": 350}}}
  }
  "Plant with integer control, u = u1 - u2"
  plant3 = DiscreteComponents.DiscreteStateSpace(nx = 2, nu = 2, ny = 2, A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], C = [[1.0, 0.0], [0.0, 1.0]], with_D = false, initialization = DiscreteComponents.InitialCondition.InitialStateArray(x0 = [10.0, 0.0])) {
    "Dyad": {"placement": {"diagram": {"x1": 340, "x2": 440, "y1": 600, "y2": 700}}}
  }
  "MPC with binary controls over the first two prediction steps only"
  mpc3 = MPCComponents.LinearMPCOptimizer(mpc = ctrl_binary2) {
    "Dyad": {"placement": {"diagram": {"x1": 180, "x2": 280, "y1": 600, "y2": 700}}}
  }
  "Continuous-time hold of the control; a model with no continuous part fails to initialize"
  zoh3 = DiscreteComponents.ZeroOrderHold() {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 510, "y2": 610}}}
  }
  periodicclock = DiscreteComponents.PeriodicClock(dt = 0.1) {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 370, "y2": 470}}}
  }
  periodicclock1 = DiscreteComponents.PeriodicClock(dt = 0.1) {
    "Dyad": {"placement": {"diagram": {"x1": 530, "x2": 630, "y1": 630, "y2": 730}}}
  }
  "Real-valued controller, u ∈ [-1, 1]"
  structural parameter ctrl_real::MPCComponents.MPCRef = build_linear_mpc(A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0], [0.1]], Np = 10, Q1 = [1.0, 1.0], Q2 = [0.1], Qf = [10.0, 10.0], umin = [-1.0], umax = [1.0], reference_tracking = false)
  "Integer controller, u1 - u2 ∈ {-1, 0, 1} over the full horizon"
  structural parameter ctrl_binary::MPCComponents.MPCRef = build_linear_mpc(A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], Np = 10, Q1 = [1.0, 1.0], Q2 = [[0.100001, -0.1], [-0.1, 0.100001]], Qf = [10.0, 10.0], umin = [0.0, 0.0], umax = [1.0, 1.0], binary_controls = [1, 2], reference_tracking = false)
  "Integer controller, binary only over the first two steps, relaxed to [0, 1] after"
  structural parameter ctrl_binary2::MPCComponents.MPCRef = build_linear_mpc(A = [[1.0, 0.1], [0.0, 1.0]], B = [[0.0, 0.0], [0.1, -0.1]], Np = 10, Q1 = [1.0, 1.0], Q2 = [[0.100001, -0.1], [-0.1, 0.100001]], Qf = [10.0, 10.0], umin = [0.0, 0.0], umax = [1.0, 1.0], binary_controls = [1, 2], Nc_binary = 2, reference_tracking = false)
  "Position, real-valued control"
  variable p1::Real
  "Velocity, real-valued control"
  variable v1::Real
  "Control signal, real-valued"
  variable u1::Real
  "Position, full binary horizon"
  variable p2::Real
  "Velocity, full binary horizon"
  variable v2::Real
  "Control signal u1 - u2, full binary horizon"
  variable u2::Real
  "Position, binary horizon 2"
  variable p3::Real
  "Velocity, binary horizon 2"
  variable v3::Real
  "Control signal u1 - u2, binary horizon 2"
  variable u3::Real
relations
  p1 = plant1.y[1]
  v1 = plant1.y[2]
  u1 = mpc1.u[1]
  p2 = plant2.y[1]
  v2 = plant2.y[2]
  u2 = mpc2.u[1] - mpc2.u[2]
  p3 = plant3.y[1]
  v3 = plant3.y[2]
  u3 = mpc3.u[1] - mpc3.u[2]
  connect(mpc1.u[1], zoh1.u, clock1.y) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [{"x": 310, "y": 113}, {"x": 310, "y": 0}], "E": 2},
        {"S": 2, "M": [], "E": 3}
      ],
      "path": {}
    }
  }
  connect(mpc2.u[1], zoh2.u, periodicclock.y) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [{"x": 310, "y": 413}, {"x": 310, "y": 300}], "E": 2},
        {"S": 2, "M": [], "E": 3}
      ],
      "path": {}
    }
  }
  connect(mpc3.u[1], zoh3.u, periodicclock1.y) {
    "Dyad": {
      "edges": [
        {"S": 1, "M": [{"x": 310, "y": 673}, {"x": 310, "y": 560}], "E": 2},
        {"S": 2, "M": [], "E": 3}
      ],
      "path": {}
    }
  }
  connect(plant1.y, mpc1.xhat) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 460, "y": 90},
            {"x": 460, "y": 180},
            {"x": 160, "y": 180},
            {"x": 160, "y": 90}
          ],
          "E": 2
        }
      ],
      "path": {}
    }
  }
  connect(plant2.y, mpc2.xhat) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 460, "y": 390},
            {"x": 460, "y": 470},
            {"x": 160, "y": 470},
            {"x": 160, "y": 390}
          ],
          "E": 2
        }
      ],
      "path": {}
    }
  }
  connect(mpc3.xhat, plant3.y) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 160, "y": 650},
            {"x": 160, "y": 730},
            {"x": 460, "y": 730},
            {"x": 460, "y": 650}
          ],
          "E": 2
        }
      ],
      "path": {}
    }
  }
  connect(mpc1.u, plant1.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 310, "y": 113}, {"x": 310, "y": 90}], "E": 2}],
      "path": {}
    }
  }
  connect(mpc2.u, plant2.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 310, "y": 413}, {"x": 310, "y": 390}], "E": 2}],
      "path": {}
    }
  }
  connect(mpc3.u, plant3.u) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 310, "y": 673}, {"x": 310, "y": 650}], "E": 2}],
      "path": {}
    }
  }
metadata {"Dyad": {"doc": {"behavior": false}}}
end


Test Cases ​

No test cases defined.

  • Examples

  • Experiments

  • Analyses