All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sv_checker.Orch.vdmsl Maven / Gradle / Ivy

There is a newer version: 1.0.10
Show newest version
/* 
  Model that formalises rule checking of FMU (Functional Mock-up Unit) scalars. The model takes as input an initial scalar
  with possibly undefined values for causality, variability and intial. First, the model
  attempts to adjust any of the undefined values. Afterwards it checks
  that the adjusted scalar follows the standard. If the adjusted scalar does follow the standard then the model
  produces a meaningful error message indicating what the specific problem with the scalar configuration is.

  Steps of individual FMU init:
  (1) Read all scalar variables from FMU (a set of SV)
  (2) Initialise the FMU according to the FMI standard,
  i.e. set the default values of the scalar properties,
  if not defined.
  (3) Validate the scalar variables of the FMU 
	according to the FMI standard
*/
module Orch

imports from IO all, from VDMUtil all
definitions

types

-- The different causalities a scalar may specify
Causality =  |  |  |  |  | ;

-- The different variabilities a scalar may specify
Variability =  |  |  |  | ;

-- The different initial values a scalar may specify
Initial =  |  | ;

Types =  |  |  |  | ;
StartValueTypes = [real | int | bool | seq of char | token];

-- The type of a scalar
Type ::
	type  : Types
	startValue : StartValueTypes;

/*
  Represents a scalar before it has been adjusted. At this point causality, variability as well as the
  initial value might be undefined, which is indicated using the 'nil' value.
*/
SV ::
	causality 	: [Causality]
	variability : [Variability]
	initial			: [Initial]
	type				: Type;
/*
 Represents a scalar after it has been adjusted. At this point only the initial value may be undefined,
 which is indicated using the 'nil' value.
*/
SV' ::
	causality 	: Causality
	variability : Variability
	initial			: [Initial]
	type				: Type

functions

TypeOk :  Type -> bool * seq of char
TypeOk (ty) == 
let mk_Type(t,s) = ty 
in 
if s=nil  or
   (t= and is_real(s))  or
   (t= and is_int(s)) or
   (t= and (is_bool(s) or s = 0 or s = 1)) or
   (t= and (is_(s,seq of char)or len s=0 )) or --or len s=0
   (t= and is_int(s))
			then mk_(true, "Combination OK")
else
	mk_(false, "Type and startvalue incompatible. Got: type " ^
	  VDMUtil`val2seq_of_char[Types](t) ^ " and start value " ^
	  VDMUtil`val2seq_of_char[StartValueTypes](s));
/*
 Construction of initial values based on the "causality/variability" table on page 48
 as well as the "initial" table on page 49
*/
CalcInitial : Causality * Variability -> [Initial]
CalcInitial(c,v) ==
cases c:
	 ->
	  if v in set {, } then
	    
	  else
	    nil, -- (A)
	 ->
	  if(v in set {, }) then
	    
	  else
	    nil, -- (B)
	 ->
	  nil,--if(v in set {, }) then  nil else nil, --(D)
	 ->
	  if(v=) then
	    
	  else 
	    if (v in set {, }) then
	      
	    else
	      nil, -- (A) and (C)
	 ->
	  if(v=) then
	    
	  else
	    if (v in set { , , , }) then
	      
	    else
	      nil, -- (A), (B) and (C)
	 -> nil--if (v=) then  nil, -- (E)
end
pre CausalityVariabilityOk(c,v).#1
post InitialOk(c,v,RESULT).#1;

/*
 Takes a scalar value with possibly undefined properties and tries to
 construct a valid scalar with the default values for the undefined
 properties. See page 46 (causality default), page 47 (continuous default)
 and page 49 (initial values)
*/
InitSV : SV -> SV'
InitSV(sv) ==
let mk_SV(c,v,i,t) = sv,
	  c' = if (c = nil) then  else c,
		v' = if (v = nil) then  else v,
		i' = if (i = nil) then CalcInitial(c', v') else i
in
  mk_SV'(c', v', i', t)
pre
let cc = if sv.causality = nil then  else sv.causality,
    vv = if sv.variability = nil then  else sv.variability
in 
  CausalityVariabilityOk(cc,vv).#1
post
let mk_SV'(c',v',i',-) = RESULT
in 
 (sv.causality = nil => c' = ) and
 (sv.variability = nil => v' = ) and
 ((sv.initial = nil and CausalityVariabilityOk(c',v').#1) => InitialOk(c',v',i').#1);


TypeVariability :  Variability * Type -> bool * seq of char
TypeVariability (v,t) ==
  if v =  => t.type =  then 
  	mk_(true,"Combination OK")
  else
  	mk_(false, "For a continuous variable the type has to be Real");
/*
 Constructs a string representation based on a valid combination of causality and variablity
 as indicated by the table on page 50
*/
ValidSettingsToStr : Causality * Variability -> seq of char
ValidSettingsToStr(c ,v) ==
if c= and v= then
  "fixed parameter"
elseif c= and v= then
  "tunable parameter"
elseif c= and v= then
  "fixed dependent parameter"
elseif c= and v= then
  "tunable dependent parameter"
elseif c= and v= then
  "discrete input"
elseif c= and v= then
  "continuous input"
elseif c= and v= then
  "constant output"
elseif c= and v= then
  "discrete output" 
elseif c= and v= then
  "continuous output"
elseif c= and v= then
  "constant local"
elseif c= and v= then
  "fixed local"
elseif c= and v= then
  "tunable local"
elseif c= and v= then
  "discrete local"
elseif c= and v= then
  "continuous local"
elseif c= and v= then
  "continuous independent"
else
  undefined
pre CausalityVariabilityOk(c,v).#1;
/*
 Assuming that the scalar is invalid check if the causality and variable is the problem (see table on page 49)
*/
CausalityVariabilityOk : Causality * Variability -> bool * seq of char
CausalityVariabilityOk(c,v) ==
if c in set {, , } and v =  then
  mk_(false, ErrorMsg(c,v))
elseif c in set {, } and v in set {, } then
  mk_(false, ErrorMsg(c,v))
elseif c= and v in set {, , , } then
  mk_(false, ErrorMsg(c,v))
elseif c in set {,} and v in set {, } then
  mk_(false, ErrorMsg(c,v))
else
  mk_(true, "Valid combination of Causality and Variability.")
post RESULT.#1 => ValidCV(c,v);

ValidCV :  Causality * Variability -> bool
ValidCV (c,v) ==
((c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=) or
(c= and v=));

  /*
 Formatting of an error message
*/
ErrorMsg : Causality * Variability -> seq of char
ErrorMsg (c,v) ==
  IO`sprintf("Invalid combination of causality and variability. For causality '%s' the expected variabilities are '%s' but got: '%s'",[c,ValidVariabilities(c),v])
pre not ValidCV(c,v);

/*
 Takes a causality and returns the valid variabilities in accordance with
 the causality/variability table on page 49
*/
ValidVariabilities : Causality -> set of Variability
ValidVariabilities(c) ==
cases c:
	 -> 	{, }, -- page 46
	 -> {, },
	 -> {, },
	 -> {, , },
	 -> { , , , , },
	 -> {}
end
post
forall v in set RESULT & CausalityVariabilityOk(c,v).#1;

/*
 Only invoked when CheckSV has returned false

 Checks if the initial value is valid based on the combination of causality and variability.
 Returns true if initial is valid - false otherwise. If initial is invalid a proper error message
 is also being returned, otherwise the message just indicates that the combination was okay.
*/
InitialOk : Causality * Variability * [Initial] -> bool * seq of char
InitialOk(c,v,i) ==
let EXPECT_SPECIFIC_VAL = "An invalid value of Initial. Actual: %s, but expected: %s " ^
        "for the combination of causality: %s and variability: %s",
    EXPECT_INITIAL_NOT_SET = "An invalid value of Initial. Actual: %s, but expected " ^ 
                "inital not to be set for the combination of causality: %s and variability: %s",
    INITIAL_NOT_DEFINED = "An invalid value of Initial. Actual: Initial not defined, " ^
    "but expected: %s for the combination of causality: %s and variability: %s",
    COMB_OK = "Initial OK"
in
cases c:
	 ->
	  mk_(i in set {}, IO`sprintf(EXPECT_SPECIFIC_VAL, [i,,c,v])), -- page 46
	 ->
	  mk_(i in set {,}, IO`sprintf(EXPECT_SPECIFIC_VAL, [i,{,},c,v])),
	 ->
	  mk_(i=nil, IO`sprintf(EXPECT_INITIAL_NOT_SET, [i,{,},c,v])),
	 ->
	  if (not(v =  => i = )) then
	    mk_(false, IO`sprintf(EXPECT_SPECIFIC_VAL, [i,,c,v]))
		elseif (not(v in set { , } => i in set {, , })) then
		  mk_(false, IO`sprintf(INITIAL_NOT_DEFINED, [i,{,,},c,v]))
		else
		  mk_(true,COMB_OK),
	 ->
	  if(not(v =  => i=)) then
	    mk_(false, IO`sprintf(INITIAL_NOT_DEFINED, [i,,c,v])) 
		elseif(not(v in set { , } => i in set {, })) then
		  mk_(false, IO`sprintf(INITIAL_NOT_DEFINED, [i,{,},c,v]))
		elseif(not (v in set { , } => i in set {, , })) then
		  mk_(false, IO`sprintf(INITIAL_NOT_DEFINED, [i,{,,},c,v]))
		else
		  mk_(true,COMB_OK),
	 ->
	  mk_(i=nil, IO`sprintf(EXPECT_INITIAL_NOT_SET, [i,{,},c,v]))
end
pre CausalityVariabilityOk(c,v).#1
post RESULT.#1 =ValidCVI(c,v,i);

ValidCVI :  Causality * Variability * [Initial] -> bool
ValidCVI (c,v,i) ==
 
(
 -- Case A:
 (i =  and ((v in set {,} and c = ) or (v =  and c in set {,})))
 or
 -- Case B:
 (i in set {,} and (v in set {,} and c in set {,}))
 or
 -- Case C:
 (i in set {,,} and (v in set {,} and c in set {,}))
 or
 -- Case D:
 (i = nil and (v in set {, } and c = ))
 or
 -- Case E:
 (i = nil and (v =  and c = ))
);

/*
 Only invoked when CheckSV has returned false. This function constructs
 an appropriate error message for the start value.

 If the problem is not the causality, variability or the initial value
 then the start value must be the problem.
*/
StartValueOk : Causality * Variability * [Initial] *  Type -> bool * seq of char
StartValueOk(c,v,i,t) ==
let startValReq = true,
		combOk = "Combination OK"
in 
cases c:
	 ->
	  if(not(i in set {, } => t.startValue <> nil)) then
	    mk_(false,InvalidStartValueToStr(startValReq,c,v,i))
	  else
	    mk_(true,combOk),-- page 46
	 ->
	  if(not(i in set {, } => t.startValue <> nil)) then 
		  mk_(false,InvalidStartValueToStr(startValReq,c,v,i)) 
	  else if (not(i =  => t.startValue = nil)) then 
		  mk_(false,InvalidStartValueToStr(not startValReq,c,v,i))
		else
		  mk_(true,combOk),
	 ->
	  if not t.startValue <> nil then
	    mk_(false,InvalidStartValueToStr(startValReq,c,v,i))
	  else
	    mk_(true,combOk),
	 ->
	  if(not(i =  => t.startValue = nil)) then 
		  mk_(false,InvalidStartValueToStr(not startValReq,c,v,i)) 
	  elseif (not(i in set {, } => t.startValue <> nil)) then 
		  mk_(false,InvalidStartValueToStr(startValReq,c,v,i))
		else
		  mk_(true,combOk),
	 ->
	  if(not(i =  => t.startValue = nil)) then 
		  mk_(false,InvalidStartValueToStr(not startValReq,c,v,i)) 
		elseif (not(i in set {, } => t.startValue <> nil)) then
		  mk_(false,InvalidStartValueToStr(startValReq,c,v,i))
		else
		  mk_(true,combOk),
	 ->
	  if not t.startValue = nil then
	    mk_(false,InvalidStartValueToStr(not startValReq,c,v,i))
	  else
	    mk_(true,combOk)
end
pre ValidCV(c,v) and ValidCVI(c,v,i);

ValidStart :  Causality * Variability * [Initial] * Type -> bool
ValidStart (c,v,i,t) == 
if (i in set{,}) or (c = ) then 
  t.startValue <> nil
elseif (i =  or c = ) then
  t.startValue = nil
elseif (c in set {,} or v = ) then
  t.startValue <> nil
else
  false;
 

InvalidStartValueToStr : bool * Causality * Variability * [Initial] -> seq of char
InvalidStartValueToStr(b,c,v,i) ==
if b then
  IO`sprintf("A start value has to be set for a combination of " ^
    "Causality: %s, Variability: %s and Initial: %s",[c, v, i])
else
  IO`sprintf("A start value is not allowed to be set for a combination " ^
    "of Causality: %s, Variability: %s and Initial: %s",[c, v, i]);
	
/*
 The main function of the specification.

 Takes as input an adjusted scalar and checks if the combination
 of properties is valid.

 The function returns a string representation of the scalar if it is valid.
 If the scalar is not valid the function produces an error message, which
 describes the problem with the specific choice of properties.
*/
Validate : SV' -> bool * seq of char
Validate(sv') ==
let mk_(tc_ok, tc_msg) = TypeOk(sv'.type)
in
if not tc_ok then 
		mk_(false, tc_msg)
else
	let mk_(vt_ok, vt_msg) = TypeVariability(sv'.variability,sv'.type)
	in
  	if not vt_ok then
    	mk_(false, vt_msg)
  	else
    	-- The combination of properties is not valid and we need to construct a suitable error message
    	--First check if causility and variability makes up an invalid combination
  		let mk_(cv_ok, cv_msg) = CausalityVariabilityOk(sv'.causality,sv'.variability)
    	in
			if not cv_ok then
		  	-- Causality and variability is not a valid combination so stop and return the error message
		  	mk_(false, cv_msg)
			else
		  	-- Causality and variability makes up a valid combination. Check if the initial value is the problem 
				let mk_(ini_ok, ini_msg) = InitialOk(sv'.causality,sv'.variability,sv'.initial)
			  	
				in
					if not ini_ok then
				  	mk_(false, ini_msg)
					else
				  	-- The initial value was also valid so the problem must be start value
						let mk_(start_ok, start_msg) = StartValueOk(sv'.causality,sv'.variability,sv'.initial,sv'.type)
					    	
						in
							if not start_ok then mk_(false, start_msg)
							else
								mk_(true, "ScalarVariable is valid")
post
RESULT.#1 = 
let mk_SV'(c,v,i,t) = sv'
in
  TypeOk(t).#1 and
	cases c:
	 	 -> 	
	    v in set {, } and
	    (i in set {/*, */} => t.startValue <> nil) and-- page 46
	    i = , -- page 46
		 -> 
	    v in set {, } and --page 46
	    i in set {,} and-- page 46
	    (i in set {, } => t.startValue <> nil) and
	    (i =  => t.startValue = nil),
		 -> 
	    v in set {, } and -- page 46
	    i = nil and		-- page 49 table
	    (v =  => t.type = ) and
	    t.startValue <> nil,
		 -> 
	    v in set { , , } and --page 49 table
	    (v =  => t.type = ) and
	    (v =  => i = ) and
	    (i =  => t.startValue = nil) and
	    (i in set {, } => t.startValue <> nil) and
	    (v in set { , } => i in set {, , }),
		 -> 
	    --v in set { , , , , } and -- A  can have any variability
	    (v =  => t.type = ) and
	    (v =  => i=) and
	    (i =  => t.startValue = nil) and
	    (i in set {, } => t.startValue <> nil) and
	    (v in set { , } => i in set {, }) and
	    (v in set { , } => i in set {, , }),
		 -> 
	    v =  and -- page 46
	    i = nil and
	    (v =  => t.type = ) and
	    t.startValue = nil
	 end;

allSv: () -> set of SV
allSv() ==
{ mk_SV(c, v, i, mk_Type(t, s))|
  v in set { , , , , , nil},
	c in set {,,,,,, nil},
	i in set {, , , nil},
	t in set {,,,,},
	s in set {2, nil}};

allC: () -> set of Causality
allC() == {,,,,,};

allV: () -> set of Variability
allV() == {,,,,};

allI: () -> set of [Initial]
allI() == {, , , nil};

allT: () -> set of Type
allT() ==
{mk_Type(t,s)|
	t in set {,,,,},
	s in set {2.2, 2, true, "INTO" , mk_token("INTO"), nil}};
  

allCV: () -> set of (Causality * Variability)
allCV() ==
{ mk_(c,v) | 
  v in set allV(),
	c in set allC()};

allCVI: () -> set of (Causality * Variability * [Initial])
allCVI() ==
{ mk_(c,v,i) | 
  v in set allV(),
	c in set allC(),
	i in set allI()};
	
allCVIT: () -> set of (Causality * Variability * [Initial] * Type)
allCVIT() ==
{ mk_(c,v,i,t) | 
  v in set allV(),
	c in set allC(),
	i in set allI(),
	t in set allT()};

allSV': () -> set of SV'
allSV'() ==
{ mk_SV'(c,v,i,t) |
  c in set allC(),
  v in set allV(),
  i in set allI(),
  t in set allT()}


traces

T_Validate:
let sv' in set allSV'()
in
  Validate(sv')


T_StartValueOk:
let mk_(c,v,i,t) in set allCVIT()
in
  StartValueOk(c,v,i,t);

T_InitialOk:
let mk_(c,v,i) in set allCVI()
in
  InitialOk(c,v,i);

T_ValidVariabilities:
let c in set allC()
in
  ValidVariabilities(c);

T_CausalityVariabilityOk:
let mk_(c,v) in set allCV()
in
  CausalityVariabilityOk(c,v);

T_CalcInit:
let mk_(c,v) in set allCV()
in
  CalcInitial(c,v);

T_InitSv:
let sv in set allSv()
in 
	  InitSV(sv);
	  
T_ValidSettingsToStr:
let mk_(c,v) in set allCV()
in
  ValidSettingsToStr(c,v)
  
T_TypeOK:
let t in set allT() 
in
	TypeOk(t)

end Orch




© 2015 - 2025 Weber Informatics LLC | Privacy Policy