La implementación de algoritmos inerciales en el ejemplo de modelado lógico de circuitos digitales.

1. Introducción


Pasamos a la segunda parte del tema dedicado a los autómatas anidados. En el primero, examinamos algoritmos recursivos, que, teniendo un modelo de autómatas anidados y conectando capacidades OOP, resultó no ser tan difícil de implementar. Pero las posibilidades de autómatas anidados no se limitan a esto. Entonces, al describir el modelo de control de los programas de autómatas, se determinaron los algoritmos de inercia, que también se basan en la idea de incorporar autómatas. Los algoritmos inerciales son difíciles de imaginar en el marco del diagrama de bloques habitual del modelo computacional, que no proporciona el retorno del control al punto que precede a la llamada al subprograma. Pero debo decir que los autómatas convencionales también prevén la abolición de las transiciones "sobre la marcha". Sin embargo, para los autómatas esto no solo se puede imaginar, sino también implementar.

Algoritmos inerciales y modelado lógico de circuitos digitales relacionados con temas. Y no tanto porque la demora por inercia le dio el nombre a la clase de algoritmos bajo consideración, sino cuánto significa el significado de las acciones retrasadas de la demora por inercia, que se transfirió al significado de su trabajo. Aunque, por supuesto, no es el nombre. En UML, se implementan algoritmos similares utilizando el concepto de estado histórico. La analogía es directa, aunque el modelado de circuitos digitales en UML, por regla general, está fuera de discusión. Es solo que las situaciones al regresar al punto de partida, si algo lo obliga a hacerlo, parecen ser las más naturales. Los ejemplos incluyen la negativa a comprar boletos, la cancelación de operaciones / transacciones bancarias, la desconexión de una conexión de red, etc. etc. Al final, como se indica en UML,sin el uso de estados históricos, la implementación de tales algoritmos no sería tan "hermosa" [1].

El tema del modelado lógico de circuitos digitales es extenso e interesante en sí mismo. Y una nueva lectura no le hace daño. Como veremos, la tecnología de programación automática puede ofrecer una forma aún mejor de describir, implementar y modelar lógicamente los circuitos digitales. De todos modos, sabremos esto, persiguiendo el objetivo principal: considerar una clase interesante, útil y, finalmente, una hermosa clase de algoritmos que es natural para los autómatas, pero bastante difícil de implementar en otros modelos computacionales.

2. Modelado lógico de circuitos digitales.


La literatura generalmente considera dos métodos de modelado de circuitos digitales: compilación y eventos. La compilación es limitada en sus capacidades, porque no tiene en cuenta los retrasos de los elementos, requiere elementos de clasificación y comentarios de última hora [2]. El método de evento no tiene tales restricciones y se basa en el seguimiento de eventos asociados con cambios en los valores de señal dentro del circuito. No consideraremos la compilación, sino que nos centraremos en comparar el evento con el método implementado en el marco de las posibilidades de programación automática, que llamaremos más adelante, en consecuencia, de manera automática.

Como ejemplo, tome el circuito de [2], que se muestra en la Fig. 1. Los diagramas de su trabajo desde la fuente se muestran en la Fig. 2. Se consideran dos opciones: con un solo retraso, cuando los elementos lógicos del circuito tienen el mismo retraso, y con un retraso distribuido, cuando los elementos B y E tienen un retraso dos veces mayor que el resto de los elementos del circuito.
imagen

Higo. 1. Un ejemplo de circuito.

imagen

Higo. 2. Ejemplos de modelado: a - un solo retraso; b - retraso distribuido.

Con el método de simulación automática, ni siquiera tiene que inventar algo, porque no es necesario crear un lenguaje suficientemente específico para describir un circuito y estructuras que implementen relaciones de circuito, y no necesita algoritmos suficientemente específicos para detectar eventos en el proceso de modelado de un circuito, que luego sirven como base para construir diagramas del circuito (para una descripción de ambos, ver [2] )

En el caso de los autómatas, se crean los modelos de elementos lógicos que son habituales para la tecnología de autómatas para el diseño de programas, que se incluyen en la biblioteca de elementos lógicos (BLE). Además, sobre la base de esta biblioteca, se crea un conjunto de procesos de autómatas paralelos que corresponden al número de elementos del circuito, entre los cuales se indican las conexiones utilizando los canales de entrada / salida de los modelos de elementos lógicos (para esto, en el entorno VKPA, las variables de proceso locales a menudo son suficientes). En conclusión, el modelo de circuito se complementa con procesos-generadores de señales de entrada y procesos de visualización de diagramas de señales.

Los resultados de la simulación del ejemplo considerado en el entorno VKPa, que se muestran en la Fig. 3 coinciden completamente con los diagramas de la Fig. 2. Es cierto que no fue posible de inmediato lograr tal coincidencia. Y no por problemas con los modelos, sino porque, de hecho, el "método de selección científica" tuvo que calcular la duración de las señales de entrada, lo que, como resultó, tiene un impacto significativo. Pero en [2] no se dijo una palabra sobre esto, ni sobre los parámetros de las señales de entrada. Se logró un acuerdo total al descubrir que 1) la duración igual a tres veces la demora es necesaria, y 2) el desplazamiento de la señal (b) en relación con la señal (a) debe ser igual a la unidad de retraso. Para explicar este problema, vea la fig. La Figura 4 muestra los diagramas de señal para diferentes duraciones de las señales de entrada (y esto sin tener en cuenta su desplazamiento).

imagen

Higo. 3. La simulación da como resultado VKPa: a - un solo retraso; b - retraso distribuido.

imagen

Higo. 4. Resultados de la simulación con diferentes duraciones de señal de entrada

Considere otro ejemplo de un circuito de la misma fuente [2]. Su esquema y diagramas de tiempo de trabajo se muestran en la fig. 5. En el marco del método del evento, para "calcular" el diagrama de tiempo, se requirieron 20 pasos de simulación (para más detalles ver [2]). Pero, como se afirma allí, se requiere un algoritmo aún más complejo y, en consecuencia, un número aún mayor de pasos si se elige el tipo de retraso inercial. En nuestro caso (el caso del método de modelado automático), teniendo el modelo anterior, necesitamos "20 clics" con el mouse para ir al diagrama de la Fig. 5, eliminando elementos innecesarios del circuito original. Los resultados de la simulación de circuito obtenida en VKPa se muestran en la Fig. 6)

imagen

Higo. 5. Un ejemplo de un circuito y su tabla de tiempos.

Además, el diagrama de la Fig. 5 agregamos paralelo al elemento OR elemento I. Gráfico d en la fig. 6 muestra su funcionamiento para el caso de un solo retraso. Si establecemos un gran retraso y establecemos el tipo de retraso de inercia, entonces el gráfico d se convertirá en una línea recta. Por lo tanto, el elemento And con un retraso de inercia mayor que un valor único no perderá el pulso generado en sus entradas por una combinación de estas señales de entrada ay b. Tenga en cuenta que manipular el tipo de retraso solo tiene sentido para elementos que tienen un retraso mayor que uno.

imagen

Higo. 6. Modelado del circuito en la Fig. 5 y el elemento Y (d).

3. Implementación de elementos lógicos.


En el caso general, cualquier elemento lógico puede representarse como una conexión en serie de dos bloques (ver Fig. 7): un elemento lógico ideal sin retraso y un bloque, que puede considerarse como retraso de propagación (retraso de transporte) o retraso de inercia [2].

imagen

Higo. 7. Modelo de elemento lógico retrasado.

Un elemento lógico ideal se implementa muy fácilmente mediante una función lógica normal, y el modelo de bloque de retraso puede representarse en forma de un modelo de autómata, un modelo universal que incluye transporte y retraso de inercia. Un modelo de tal retraso universal se muestra en la Fig. 8, y los modelos de autómatas anidados para él se muestran en la Fig. 9. Su implementación en C ++ y como parte de la tecnología de programación automatizada se muestra en el Listado 1.

imagen

Higo. 8. El modelo de demora universal.

imagen

Higo. 9. Modelos de autómatas anidados para retraso universal.

Las máquinas de la Fig. 8 y fig. 9 son fusiles de asalto mixtos de Mili-Moore. El funcionamiento del autómata principal en la Fig. 8. comienza creando variables locales e inicializando las referencias en la acción y12 (el predicado x12 verifica todo esto). El estado intermedio "ss" es necesario para que el predicado x3 funcione correctamente, que tiene un enlace a una variable de entrada, que puede no inicializarse. Desde el estado "ss", el modelo entra en el estado correspondiente a la salida de retardo, mientras causa un autómata anidado. Tenga en cuenta que las acciones bajo los estados de un autómata (acciones de autómatas de Moore) se iniciarán solo después de que se complete la operación de un autómata anidado. Finalmente establecerán el valor de retraso actual y el estado de la variable de salida.

La acción y13, si se define un valor de retraso, crea el autómata anidado necesario según el tipo de retraso. El autómata de retardo de transporte incorporado simplemente cuenta el valor establecido de los ciclos de reloj de tiempo discreto (la duración del retraso está determinada por el número de ciclos de reloj discreto), y el retraso de inercia controla adicionalmente el nivel de señal de entrada. En este caso, observamos que el valor devuelto del predicado x3 depende del estado actual del autómata de nivel superior.

La implementación de autómatas en la Fig. 8, 9 refleja el Listado 3. Considerando el código, debe prestar atención al método virtual f (), que, por un lado, implementa una u otra función lógica abstracta superpuesta y, por otro lado, realiza, si se especifica, una inversión. Todo esto es necesario para la implementación de modelos derivados de elementos lógicos. El Listado 2 demuestra la implementación de tal puerta NAND.

Listado 1. Implementación de un elemento lógico de retardo universal
#include "lfsaappl.h"

extern LArc TBL_DiscreteTime[];
class FDiscreteTime :											
	public LFsaAppl											
{													
public:													
    enum {cvarINE, cvarExlusiveOR, cvarOrNot};
    void MooreAction();
	bool	FCreationOfLinksForVariables();								
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF) return new FDiscreteTime(nameFsa); }
	bool FInit();											
    FDiscreteTime(string strNam, LArc* pTBL = TBL_DiscreteTime);
	~FDiscreteTime(void);										
	CVar *pVarType;		// delay type 0-transport; 1- inertial
	CVar *pVarX1;		// input variable
	CVar *pVarStrNameX1;	// input variable name
    	CVar *pVarIfNotX1;	// inverse of the first input variable
    	CVar *pVarY1;		// output variable
	CVar *pVarStrNameY1;	// output variable name
	CVar *pVarValue01;	// delay value from 0 to 1
	CVar *pVarValue10;	// delay value from 1 to 0
    	CVar *pVarNegationY;// output inversion 0 - no inversion; 1- inversion
    	virtual int x3();	// input analysis
	virtual int x12();	// link setup analysis
    	virtual bool f();
    	int nTypeElement;
protected:
// predicates												
    int x1();
// actions												
	void y1(); void y4(); void y5(); void y6(); void y7(); void y12(); void y13(); 
    bool bType{false};	// delay type: false - transport; true - inertial;
    bool bX1{false};
    int nCurrent{0};
    int nDelay{0};		// tech. delay counter value
    LFsaAppl	*pFCall{nullptr};
    friend class FCallTransport;
    friend class FCallInertial;
};		

class FCallTransport :
	public LFsaAppl
{
public:
	void MooreAction();
	FCallTransport(FDiscreteTime	*pFDiscreteTime);
	FDiscreteTime	*pFDiscreteTime;
protected:
	int x1();
};

class FCallInertial :
	public LFsaAppl
{
public:
	void MooreAction();
	FCallInertial(FDiscreteTime	*pFDiscreteTime);
	FDiscreteTime	*pFDiscreteTime;
protected:
    int x1(); int x3();
};

#include "stdafx.h"
#include "FDiscreteTime.h"											
#include "VARFSA/SetVarFsaLibrary.h"
//=====================================================================
//		Delay model at the upper structural level of the view
//=====================================================================
LArc TBL_DiscreteTime[] = {
    LArc("st",	"st","^x12","y12"),	//
    LArc("st",	"ss","x12", "--"),	//
    LArc("ss",	"s1","x3",  "y7y6y13"),// transition to a single state
    LArc("ss",	"s0","^x3", "y4y5y13"),// transition to zero state
// creation of a nested automaton at the transition to a single state
    LArc("s0",	"s1","x3",  "y13"),    
// creation of a nested automaton at the transition to the zero state
    LArc("s1",	"s0","^x3", "y13"),    
    LArc()
};
FDiscreteTime::FDiscreteTime(string strNam, LArc* pTBL):
    LFsaAppl(pTBL, strNam, nullptr, nullptr)
{ }
													
FDiscreteTime::~FDiscreteTime(void) { if (pFCall) delete pFCall; }

bool FDiscreteTime::FInit() {										
    FCreationOfLinksForVariables();
    return true;
}

bool FDiscreteTime::FCreationOfLinksForVariables()
{
// Local variables
    pVarNegationY = CreateLocVar("negation", CLocVar::vtBool, "output inversion: 0-without inversion / 1-inversion");
    pVarType = CreateLocVar("type", CLocVar::vtBool, "delay type: 0-transp / 1-inertia");
    pVarY1 = CreateLocVar("y", CLocVar::vtBool, "local output");
    pVarX1 = CreateLocVar("x1", CLocVar::vtBool, "local input");
    pVarValue01 = CreateLocVar("value to 1", CLocVar::vtInteger, "delay value from 0 to 1");
    pVarValue10 = CreateLocVar("value to 0", CLocVar::vtInteger, "delay value from 1 to 0");
    pVarStrNameX1 = CreateLocVar("strNameX1", CLocVar::vtString, "name of external input variable (x)");
    pVarStrNameY1 = CreateLocVar("strNameY", CLocVar::vtString, "name of external output variable (y)");
    pVarIfNotX1 = CreateLocVar("not(x1)", CLocVar::vtBool, "1st input inversion: 0-without inversion / 1-inversion");
    string str;
    str = pVarStrNameX1->strGetDataSrc();
    if (str != "") { pVarX1 = pTAppCore->GetAddressVar(pVarStrNameX1->strGetDataSrc().c_str(), this);	}
    str = pVarStrNameY1->strGetDataSrc();
    if (str != "") { pVarY1 = pTAppCore->GetAddressVar(pVarStrNameY1->strGetDataSrc().c_str(), this);	}
    return true;
}
// predicates
int FDiscreteTime::x1() { return nCurrent == nDelay; }
//  
int FDiscreteTime::x3() {
    if (bool(pVarNegationY->GetDataSrc())) return !f();
    return f();
}
//
int FDiscreteTime::x12() { return pVarX1 != nullptr; }
//
bool FDiscreteTime::f() {
    bX1 = bool(pVarX1->GetDataSrc());
    if (bool(pVarIfNotX1->GetDataSrc())) bX1 = !bX1;
    return bX1;
}
// actions
// +1 to the current delay value
void FDiscreteTime::y1() { nCurrent++; }
// setting the delay value when switching from 0 to 1
void FDiscreteTime::y4() { nDelay = int(pVarValue01->GetDataSrc()); }
// setting output to zero
void FDiscreteTime::y5() { pVarY1->SetDataSrc(nullptr, 0.0); }
// setting output to unit
void FDiscreteTime::y6() { pVarY1->SetDataSrc(nullptr, 1); }
// setting the delay value when switching from 1 to 0
void FDiscreteTime::y7() { nDelay = int(pVarValue10->GetDataSrc()); }
//
void FDiscreteTime::y12() { FInit(); }
// creation, if a delay is determined, of the necessary nested automaton
void FDiscreteTime::y13() {
	nCurrent = 0;
	if (pFCall) { delete pFCall; pFCall = nullptr; }
	if (x1()) return;
	bType = pVarType->GetDataSrc();		// set delay type
	if (bType) pFCall = new FCallInertial(this);
	else pFCall = new FCallTransport(this);
	if (pFCall) pFCall->FCall(this);
}

void FDiscreteTime::MooreAction()
{
	string strState = FGetState();
	if (strState=="s0")	{ 
        y4(); y5();		// y4) setting the delay value when switching from 0 to 1; y5) set the output to zero
    }
	else if (strState=="s1") { 
        y7(); y6();		// y7) setting the delay value when switching from 1 to 0; y6) setting the output to one
    }
}
//=====================================================================
//				Transport delay
//=====================================================================
static LArc TBL_CallTransport[] = {
	LArc("s5","s5","^x1",	"--"),		//
	LArc("s5","00","x1",	"--"),		// 
	LArc()
};

FCallTransport::FCallTransport(FDiscreteTime	*pFI):
    LFsaAppl(TBL_CallTransport, "FCallTransport", nullptr, nullptr)
{
	pFDiscreteTime = pFI;
}
// . == 
int FCallTransport::x1() { return pFDiscreteTime->x1(); }
//
void FCallTransport::MooreAction()
{
	string strState = FGetState();
	if (strState=="s5")	{ pFDiscreteTime->y1(); }
}
//=====================================================================
//				Inertial delay
//=====================================================================
static LArc TBL_CallInertial[] = {
	LArc("s5",	"s5","^x1x3",	"--"),		//
	LArc("s5",	"00","x1x3",	"--"),		//
	LArc("s5",	"XX","^x3",	"--"),		//
	LArc()
};

FCallInertial::FCallInertial(FDiscreteTime	*pFI):
    LFsaAppl(TBL_CallInertial, "FCallInertial", nullptr, nullptr)
{
	pFDiscreteTime = pFI;
}
// . == 
int FCallInertial::x1() { return pFDiscreteTime->x1(); }
// input value (depends on the name of the current state of the main automaton)
int FCallInertial::x3() {
	string strState = FGetStateUp();
	bool bX = pFDiscreteTime->x3();
    if (strState == "s0") return bX;
    if (strState == "s1") return !bX;
	if (strState == "st") {
		string str = pFDiscreteTime->FGetNextState();
		bX = pFDiscreteTime->x3();
		if (!bX) {
			if (x1()) {
                if (str == "s0") return !bX;
                if (str == "s1") return bX;
			}
            else return true;
		}
		return true;
	}
	else return bX; 
}
//
void FCallInertial::MooreAction()
{
	string strState = FGetState();
	if (strState=="s5")	{ pFDiscreteTime->y1(); }
}


Listado 2. Implementando una puerta NAND
#include "lfsaappl.h"

#include "../FDiscreteTime.h"
extern LArc TBL_DiscreteTime[];
class FIne :
	public FDiscreteTime
{
public:
    bool	FCreationOfLinksForVariables() override;
    LFsaAppl* Create(CVarFSA *pCVF) override { Q_UNUSED(pCVF) return new FIne(nameFsa); }
    bool FInit() override;
    FIne(string strNam, LArc* TBL = TBL_DiscreteTime);
    ~FIne(void);
	CVar *pVarX2;		//  
	CVar *pVarStrNameX2;	//    
	CVar *pVarIfNotX2;	//    
	virtual bool f() override;
protected:
    	int x12() override;
    	bool bX2;
};

#include "stdafx.h"
#include <Ine/FIne.h>
#include "VARFSA/SetVarFsaLibrary.h"

FIne::FIne(string strNam, LArc* pTBL):
    FDiscreteTime(strNam, pTBL)
{
    nTypeElement = FDiscreteTime::cvarINE;
}

FIne::~FIne(void) { }

bool FIne::FInit() {										
// 	 		
	FCreationOfLinksForVariables();
//	 										
	return true;										
}

bool FIne::FCreationOfLinksForVariables() {
//  
	FDiscreteTime::FCreationOfLinksForVariables();
	//      x1, x2
    pVarIfNotX2 = CreateLocVar("not(x2)", CLocVar::vtBool, " 2- : 0- /1-");
	pVarX2 = CreateLocVar("x2", CLocVar::vtBool, " 2- ");
    //  ,         x2
	pVarStrNameX2 = CreateLocVar("strNameX2", CLocVar::vtString, "  2- .(x)");
	// :   ,     
    string str = pVarStrNameX2->strGetDataSrc();
    if (str != "") { pVarX2 = pTAppCore->GetAddressVar(pVarStrNameX2->strGetDataSrc().c_str(), this); }
//
	return true;
}
//
int FIne::x12() { return FDiscreteTime::x12() && pVarX2 != nullptr; }
//
bool FIne::f() {
    //  1- 
    FDiscreteTime::f();
    //   
    bX2 = bool(pVarX2->GetDataSrc());
    if (bool(pVarIfNotX2->GetDataSrc())) bX2 = !bX2;
    //   : 
    return bX1&&bX2;
}


Gracias a OOP, el código del modelo del elemento lógico Y NO es notablemente más pequeño que el código del retraso "principal". Además, está determinado en gran medida por la necesidad de crear una entrada adicional para el modelo del elemento AND. Si, a nivel estructural, los modelos coinciden con el número de entradas / salidas, entonces el código será aún más pequeño. Entonces, el código de implementación para la puerta XOR generado a partir de un modelo estructuralmente similar del elemento AND-NOT se muestra en el Listado 3.

Listado 3. Implementación exclusiva de puerta de enlace OR
#include <Ine/FIne.h>

extern LArc TBL_DiscreteTime[];
class FExlusiveOR :
    public FIne
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { return new FExlusiveOR(nameFsa); }
    FExlusiveOR(string strNam, LArc* TBL = TBL_DiscreteTime);
    ~FExlusiveOR(void);
protected:												
    bool f();
};

#include "stdafx.h"
#include "FExlusiveOR.h"

FExlusiveOR::FExlusiveOR(string strNam, LArc* pTBL):
    FIne(strNam, pTBL)
{
    nTypeElement = FDiscreteTime::cvarExlusiveOR;
}

FExlusiveOR::~FExlusiveOR(void) { }
//
bool FExlusiveOR::f() {
    FIne::f();
    return (bX1&&bX2)||(!bX1&&!bX2);
}


Aquí, el método f () de la clase FExlusiveOR llama al método f () de la clase FIne solo para leer los valores de las variables de entrada, y luego se superpone el valor de la función NAND con el valor calculado de acuerdo con la función lógica de la nueva clase. A imagen y semejanza, se pueden crear modelos de cualquier otro elemento lógico de dos entradas.

3 Conclusiones


Para implementar cualquier circuito digital, el llamado conjunto funcionalmente completo de elementos lógicos es suficiente. Puede ser, por ejemplo, un conjunto de elementos AND, OR, NOT. Examinamos la implementación de los siguientes elementos lógicos: retrasos, que pueden ser un inversor, elementos AND-NOT y EXCLUSIVE OR. Se relacionan con los elementos básicos que forman parte de un conjunto funcionalmente completo. Para implementar y / o simular cualquier esquema, queda por agregar a la biblioteca, por ejemplo, un elemento OR-NOT o implementar un elemento personalizado universal que esté configurado para un elemento de un conjunto funcionalmente completo. Y ya será suficiente.

Como resultado, sobre la base de los modelos anteriores, tenemos frente al entorno CPSU un entorno completo para el modelado lógico de circuitos digitales, que le permite generar cualquier número de procesos desde cualquier elemento de la biblioteca, configurarlos y establecer conexiones entre ellos. Al mismo tiempo, la simulación será más detallada (teniendo en cuenta todos los tipos de retrasos), más flexible (puede configurar los elementos individualmente) que en el caso de los dos métodos de modelado lógico típicos mencionados anteriormente: compilación y evento. Y no será un entorno especializado, como El modelo de los procesos de software permanece sin cambios; seguirá siendo tan universal como cualquier otro entorno de programación orientado a objetos basado en el uso del lenguaje C ++.

Y más sobre ... dolor. Érase una vez, frente a lo que está mal en la literatura científica o, más exactamente, una descripción de un elemento lógico clave como un disparador RS es realmente analfabeto, así como el hecho de que incluso los ingenieros electrónicos geniales no saben cómo funciona en detalle gatillo, pasé mucho tiempo para resolver esto. Y puedo informar que en este momento en el problema de activación, al menos para mí no hay espacios en blanco (ver detalles [3]). Y por lo tanto, solo queda sorprenderse de que, en general, nada esté cambiando. Como la descripción tabular del desencadenante se dio anteriormente, todavía se da hoy, ya que existían los notorios estados prohibidos, y se mantuvieron igual cuando se quejaron del cambio impredecible del disparador al salir del estado prohibido, por lo que todavía están en la misma ignorancia. Y esto a pesar deque ya se conocen ejemplos de una descripción suficientemente precisa de su comportamiento (véase, por ejemplo, [4]).

En verdad, "Tus obras son maravillosas, Señor!" No, al parecer, en la cabeza de tales "descriptores de disparo RS" ... programación automática y el método considerado de modelar circuitos lógicos en el entorno VKPa. Y si vuelve al tema del artículo, entonces, por ejemplo, utilizando el modelo anterior del elemento NAND, puede crear fácilmente un modelo de disparo y simular su operación en detalle. Incluyendo tener en cuenta las propiedades de los elementos lógicos reales que solo tienen un tipo de retraso inercial. Bueno, si necesita una prueba formal de las propiedades de un desencadenante, se proporciona en [5].

Literatura
1. ., ., . UML. . . : , 2007. – 493 .
2. ., ., . : . . – .: , 1988. – 309 .
3. . [ ], : habr.com/ru/post/484588 . . . ( 07.01.2020).
4. . . 2- . – .: , 2004. – 432.
5. .. . [ ], : cloud.mail.ru/public/HwsK/T95PMM8Ed . . . ( 01.02.2020).

All Articles