Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
M MTSA
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 68
    • Issues 68
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Metrics
    • Incidents
    • Environments
  • Packages & Registries
    • Packages & Registries
    • Package Registry
  • Analytics
    • Analytics
    • CI/CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • lafhis
  • MTSA
  • Issues
  • #71

Closed
Open
Created May 26, 2025 by Pablo Laciana@placianaOwner

Unrealizable control problems should abort construction of model

If I build the composition of a controller with its environment, and the construction of the composition fails, then the construction of the composition should fail.

In the following example, the controller cannot be built and instead a C_#NC# is built and composed with Plant.

‌

//Example taken from Nicolas D'Ippolito's thesis. Section 4.61
//Use of the failures keyword.
//Compose "Compatible" to check if assumptions are compatible with the control problem.
//Compose "C" to build the controller.

const N = 2
range ProductCount = 1..N
set ProductTypes = {a, b}
set Toolset = {drill,oven,press}
set ProductsTypeA = {{a}.[ProductCount]}
set ProductsTypeB = {{b}.[ProductCount]}
set ProductTypesSet = {ProductsTypeA, ProductsTypeB}
set BlankAlpha = {[ProductTypesSet].{inTray, getInTray, putOutTray, getInTrayOk, getInTrayFail}, {put}.Toolset.[ProductTypesSet]}
set ArmAlpha = { [ProductTypesSet].{getInTray, putOutTray}, {put, get, getOk, getFail}.Toolset.[ProductTypesSet] }
set ToolsAlpha = { {put, get}.Toolset.[ProductTypesSet] }
set Alphabet = {ArmAlpha, ToolsAlpha, BlankAlpha}
set ControllableActions = {[ProductTypesSet].{getInTray}}

set FailuresSet = {{getFail}.Toolset.[ProductTypesSet], [ProductTypesSet].{getInTrayFail}}

INIT_PRODUCT(C=1) = ([C].inTray -> TRY_GET_INTRAY),
TRY_GET_INTRAY = ([C].getInTray -> ([C].getInTrayOk-> END | [C].getInTrayFail -> TRY_GET_INTRAY)).
TRY_TOOL(T='any, C=1) = (put[T][C] -> TRY_GET),
TRY_GET = (get[T][C]-> (getOk[T][C] -> END | getFail[T][C]->TRY_GET)).
FINISH_PRODUCT(C=1) = ([C].putOutTray -> END).

PRODUCT_A(C=1)= INIT_PRODUCT(C);
TRY_TOOL('oven,C);
TRY_TOOL('drill,C);
TRY_TOOL('press,C);
FINISH_PRODUCT(C);
PRODUCT_A.

PRODUCT_B(C=1)= INIT_PRODUCT(C);
TRY_TOOL('drill,C);
TRY_TOOL('press,C);
TRY_TOOL('oven,C);
FINISH_PRODUCT(C);
PRODUCT_B.

compose ||PRODUCT_PROCESS = (forall[a:ProductsTypeA] PRODUCT_A(a) || forall[b:ProductsTypeB] PRODUCT_B(b)).

RAW_PRODUCT(C=1) = ([C].inTray -> READY_INTRAY | [C].idle -> RAW_PRODUCT ),
READY_INTRAY = ([C].getInTray -> ([C].getInTrayOk->TOOLS_AVAIL | [C].getInTrayFail->READY_INTRAY)),
TOOLS_AVAIL = (put[t:Toolset][C] -> TO_GET[t] | [C].putOutTray -> RAW_PRODUCT),
TO_GET[t:Toolset] = (get[t][C] -> (getOk[t][C]->TOOLS_AVAIL | getFail[t][C]->TO_GET[t])).

||RAW_PRODUCTS = forall[p:ProductTypesSet] RAW_PRODUCT(p).

TOOL(T='any) = (put[T][e:ProductTypesSet] -> process[T][e] -> TRY_GET[e]),
TRY_GET[e:ProductTypesSet] = (get[T][e] -> GET_TOOL[e]),
GET_TOOL[e:ProductTypesSet] = ( getFail[T][e]->TRY_GET[e] | getOk[T][e]->TOOL).

||TOOLS = (forall[t:Toolset] TOOL(t)).

ARM = IDLE,
IDLE = ([e:ProductTypesSet].getInTray -> IN_TRAY[e] | get[t:Toolset][e:ProductTypesSet] -> GET_TOOL[t][e]),
GET_TOOL[t:Toolset][e:ProductTypesSet] = ( getOk[t][e]->PICKED_UP[e] | getFail[t][e]->IDLE),
IN_TRAY[e:ProductTypesSet] = ([e].getInTrayOk->PICKED_UP[e] | [e].getInTrayFail->IDLE),
PICKED_UP[e:ProductTypesSet] = (put[t:Toolset][e] -> IDLE | [e].putOutTray -> IDLE).

||Plant = (forall[p:ProductTypesSet] RAW_PRODUCT(p) || forall[t:Toolset] TOOL(t) || ARM).

||A = (PRODUCT_A).

fluent TOOL_PROCESS[e:ProductTypesSet][t:Toolset] = <put[t][e], getOk[t][e]>
ltl_property CANT_PROCESS_SIMULTANEOSLY = [](! exists[a:ProductTypesSet][b:ProductTypesSet]
(TOOL_PROCESS[a]['drill] && TOOL_PROCESS[b]['oven]))

fluent ADDED_TO_OUTTRAY[e:ProductTypesSet] = <[e].putOutTray, Alphabet{[e].putOutTray}>
//The ending action needs to be getInTray, so the controller can't postpone an element indefinitely
fluent ADDED_TO_INTRAY[e:ProductTypesSet] = <[e].inTray, [e].getInTrayOk>
fluent BEING_PROCESSED[e:ProductTypesSet] = <[e].getInTrayOk, [e].putOutTray>
fluent F_Failures = <FailuresSet, Alphabet{FailuresSet}>

assert ASSUME_ON_A1 = (ADDED_TO_INTRAY['a[1]] || BEING_PROCESSED['a[1]])
assert ASSUME_ON_B1 = (ADDED_TO_INTRAY['b[1]] || BEING_PROCESSED['b[1]])
assert ASSUME_ON_A2 = (ADDED_TO_INTRAY['a[2]] || BEING_PROCESSED['a[2]])
assert ASSUME_ON_B2 = (ADDED_TO_INTRAY['b[2]] || BEING_PROCESSED['b[2]])

assert GOAL_FOR_A = exists[e:ProductsTypeA] (ADDED_TO_OUTTRAY[e])
assert GOAL_FOR_B = exists[e:ProductsTypeB] (ADDED_TO_OUTTRAY[e])

assert Failures = F_Failures

controller ||C = (Plant)~{G1}.
checkCompatibility ||Compatible = (Plant)~{G1}.

controllerSpec G1 = {
safety = {PRODUCT_PROCESS, CANT_PROCESS_SIMULTANEOSLY}
failure = {Failures}
assumption = {}
liveness = {GOAL_FOR_A, GOAL_FOR_B}
controllable = {ControllableActions}
}

||SYS = (C || Plant).

‌

Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking