diff --git a/docs/extensions.md b/docs/extensions.md new file mode 100644 index 00000000..24325a8b --- /dev/null +++ b/docs/extensions.md @@ -0,0 +1,44 @@ +--- +layout: default +title: IDeSyDe - Extensions +description: { { site.description } } +permalink: /extensions +usemathjax: true +--- + + +# Extensions + +This page contains two tutorials on how to construct extensions for IDeSyDe in two different manners: +one for JVM languages, but using Java as the main example; and one for a Rust embedded module. + +## Java module + +To create a new java module, first make sure that JDK and `gradle` are installed in your computer. +You can follow the steps from the [ForSyDe IO website](https://forsyde.github.io/forsyde-io/usage/#optional-downloading-sdk-gradle-and-jabba) +using SDKMan and Jabba. + +Once `gradle` is installed, go to a folder in your computer where you wish to develop and build the module and issue: + +``` +gradle init +``` + +which ask you what type of project you wish to create and then create a handful of files in the directory that we will work with. +Ideally you should choose `application` as the most basic one, in case you do not fully know how to work with Maven/Gradle based JVM projects. +Among the questions asked, you can choose the default for most, except for the minimum java version, which should be 17. +Don’t worry if this number seems high to you, it is the latest LTS after 11, and it will be supported for many years; +it is just that Java moves slowly but surely, specially its using companies. + +The most import file for now is `build.gradle`, which declaratively defines the project’s dependencies and also fetches them. +To fetch the framework parts of IDeSyDe, you need to first enable JitPack as a repository: + +``` +repositories { + maven { url '' } +} +``` + +And then add to the modules to the dependencies section of your build.gradle: + +## Rust embedded module diff --git a/docs/extensions/decisionModel.md b/docs/extensions_old/decisionModel.md similarity index 98% rename from docs/extensions/decisionModel.md rename to docs/extensions_old/decisionModel.md index 45d55acb..a77b20d8 100644 --- a/docs/extensions/decisionModel.md +++ b/docs/extensions_old/decisionModel.md @@ -1,123 +1,123 @@ ---- -layout: default -permalink: /extensions/decisionModel ---- - -# Decision models - -## Fundamentals - -Let's start with how decision models are defined, taken from the [design space identification proposal paper](https://ieeexplore.ieee.org/abstract/document/9474082): - -> Design space exploration requires models into "solvable" representations; such as genome encoding for genetic algorithms (GAs), -> constraint programs for constraint programming (CP), or linear mathematical formulas for mixed integer linear programming (MILP). -> These models are called decision models. - -This tells us that besides the actual problem-specific parameters and methods that we want -to program, we need to add a handful "extras" for so that the identification procedure works properly. -In essence, these extras are defining what is the type of the elements ([`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#ElementT-0)) and the type of -the element relationships ([`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#ElementRelationT-0)) that this new @scaladoc[DecisionModel](idesyde.identification.DecisionModel) -is abstracting. Besides that, we need to provide how these custom types can be transformed to `String`s, -since that is the _de-facto_ common ground for unique identifiers that are also minimally understandable. -Finally and most importantly, we need to provide a set of [`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#coveredElements-0) and a set of [`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#coveredElementRelations-0). -This is fundamental because the identification procedure depends on this in order to: 1) terminate and converge to a unique value, -and 2) converge to the _correct_ value. Therefore, these choices are not to be taken lightly as they can mean -the difference between IDeSyDe working as expected and not. - -However, this discussion also suggests a good starting point for an abstracted element: if they have to be -stringifiable to an unique `String` identifier, why not make the elements of the @scaladoc[DecisionModel](idesyde.identification.DecisionModel) -`String`s themselves? That's exactly the path taken with @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel). -We could still go on with a very custom element type (`ElementT`), but them we have to guarantee that every distinct element -in the model will always generate a unique identifier. - -## The standard decision model - -Building on top of @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel) adds a new dependency to our -new extensions: the `scala-common` module. Some might think that adding dependencies is always risky, but this one particular dependency -is *highly recomended*. The cde in this module - can greatly simplify life with IDeSyDe, since most of the "vendor-agnostic" stuff is in this module, including -the aforementioned @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel), but also other -children decision models encoding known design scenarios from the scientific and engineering literature. - -Moving on, now the only required to implement the trait @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel) -is to return a set of strings and set of pairs of strings. - -For example, let's take the decision model @scaladoc[SharedMemoryMultiCore](idesyde.identification.common.models.platform.SharedMemoryMultiCore) from `scala-common` , which abstracts a shared-memory multi-core hardware architecture. Although there are -a handful of parameters that describe many performance characteristics of the architecture, the covered elements are fewer; namely, -they are the processing elements, the memory elements and the communication elements: - -@@snip [SharedMemoryMultiCore.scala](/scala-common/src/main/scala/idesyde/identification/common/models/platform/SharedMemoryMultiCore.scala) { #covering_documentation_example } - -where the elements being aggregated are simply lists of strings. - -## A step-by-step example - -Now that we know to use @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel), let's do a step-by-step construction of a new decision model. In this tutorial, we shall -create the parameters that abstract nicely [Synchronous Dataflow (graphs)](https://ieeexplore.ieee.org/document/1458143) or SDF(Gs), for short. - -Since SDFs are essentially labelled directed graphs, we can start with the graph part. Every directed graph must have a set of nodes and -a set of arcs, which are called actors and channels in SDF terminology. Thus, we could start writing the decision model class like: - -``` -final case class SDFApplication( - val actors: Vector[String], - val channelsSrcs: Vector[String], - val channelsDsts: Vector[String], -) extends StandardDecisionModel { - - val coveredElements = actors.toSet - val coveredElementRelations = channelsSrcs.zip(channelDsts).toSet - def uniqueIdentifier = "SDFApplication" - -} -``` - -Although this captures the graph part, now we are missing the "labelled" part of it: the data rates. Since SDFs have -fixed production and consumption rates, and they always exist for every channels, we could add to the decision simply via: - -``` -final case class SDFApplication( - val actors: Vector[String], - val channelsSrcs: Vector[String], - val channelsDsts: Vector[String], - val production: Vector[Int], - val consumption: Vector[Int], -) extends StandardDecisionModel { - - val coveredElements = actors.toSet - val coveredElementRelations = channelsSrcs.zip(channelDsts).toSet - def uniqueIdentifier = "SDFApplication" - -} -``` - -which would take care of it. Note that the covered elements have not changed! This does not mean that the decision model created -is wrong, because we added information that is conceptually identified from the same elements and their relations. That is, we "know" -from the model definition that the production and consumption rates are part of the channel definition, and therefore it is not -a problem that new information was added to the decision model _while_ the covered elements and relations remained the same. -A final key elements we are missing is the initial tokens present in each channel. Once more, since we were supposed to start with -this information, it makes sense that no new element is being covered by this decision model extension. - -``` -final case class SDFApplication( - val actors: Vector[String], - val channelsSrcs: Vector[String], - val channelsDsts: Vector[String], - val production: Vector[Int], - val consumption: Vector[Int], - val numInitialTokens: Vector[Int] -) extends StandardDecisionModel { - - val coveredElements = actors.toSet - val coveredElementRelations = channelsSrcs.zip(channelDsts).toSet - def uniqueIdentifier = "SDFApplication" - -} -``` - -And there we have it! The most basic decision model representing SDFs, without taking into consideration execution times, actors sizes etc. -One could checkout the actual decision model for SDFs in `scala-model`: @scaladoc[SDFApplication](idesyde.identification.common.models.sdf.SDFApplication) and see differences. This is because the SDF decision model in the common module also takes into consideration the practical -factors briefly mentioned in order to later perform design space exploration on top of this decision model. - -That's it! This is how one would create a correcy decision model, @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel) specifically, so that it is a expected for the identification procedure. From here, it would now be +--- +layout: default +permalink: /extensions/decisionModel +--- + +# Decision models + +## Fundamentals + +Let's start with how decision models are defined, taken from the [design space identification proposal paper](https://ieeexplore.ieee.org/abstract/document/9474082): + +> Design space exploration requires models into "solvable" representations; such as genome encoding for genetic algorithms (GAs), +> constraint programs for constraint programming (CP), or linear mathematical formulas for mixed integer linear programming (MILP). +> These models are called decision models. + +This tells us that besides the actual problem-specific parameters and methods that we want +to program, we need to add a handful "extras" for so that the identification procedure works properly. +In essence, these extras are defining what is the type of the elements ([`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#ElementT-0)) and the type of +the element relationships ([`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#ElementRelationT-0)) that this new @scaladoc[DecisionModel](idesyde.identification.DecisionModel) +is abstracting. Besides that, we need to provide how these custom types can be transformed to `String`s, +since that is the _de-facto_ common ground for unique identifiers that are also minimally understandable. +Finally and most importantly, we need to provide a set of [`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#coveredElements-0) and a set of [`coveredElements`](/$scaladoc.base_url$/idesyde/identification/DecisionModel.html#coveredElementRelations-0). +This is fundamental because the identification procedure depends on this in order to: 1) terminate and converge to a unique value, +and 2) converge to the _correct_ value. Therefore, these choices are not to be taken lightly as they can mean +the difference between IDeSyDe working as expected and not. + +However, this discussion also suggests a good starting point for an abstracted element: if they have to be +stringifiable to an unique `String` identifier, why not make the elements of the @scaladoc[DecisionModel](idesyde.identification.DecisionModel) +`String`s themselves? That's exactly the path taken with @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel). +We could still go on with a very custom element type (`ElementT`), but them we have to guarantee that every distinct element +in the model will always generate a unique identifier. + +## The standard decision model + +Building on top of @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel) adds a new dependency to our +new extensions: the `scala-common` module. Some might think that adding dependencies is always risky, but this one particular dependency +is *highly recomended*. The cde in this module + can greatly simplify life with IDeSyDe, since most of the "vendor-agnostic" stuff is in this module, including +the aforementioned @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel), but also other +children decision models encoding known design scenarios from the scientific and engineering literature. + +Moving on, now the only required to implement the trait @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel) +is to return a set of strings and set of pairs of strings. + +For example, let's take the decision model @scaladoc[SharedMemoryMultiCore](idesyde.identification.common.models.platform.SharedMemoryMultiCore) from `scala-common` , which abstracts a shared-memory multi-core hardware architecture. Although there are +a handful of parameters that describe many performance characteristics of the architecture, the covered elements are fewer; namely, +they are the processing elements, the memory elements and the communication elements: + +@@snip [SharedMemoryMultiCore.scala](/scala-common/src/main/scala/idesyde/identification/common/models/platform/SharedMemoryMultiCore.scala) { #covering_documentation_example } + +where the elements being aggregated are simply lists of strings. + +## A step-by-step example + +Now that we know to use @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel), let's do a step-by-step construction of a new decision model. In this tutorial, we shall +create the parameters that abstract nicely [Synchronous Dataflow (graphs)](https://ieeexplore.ieee.org/document/1458143) or SDF(Gs), for short. + +Since SDFs are essentially labelled directed graphs, we can start with the graph part. Every directed graph must have a set of nodes and +a set of arcs, which are called actors and channels in SDF terminology. Thus, we could start writing the decision model class like: + +``` +final case class SDFApplication( + val actors: Vector[String], + val channelsSrcs: Vector[String], + val channelsDsts: Vector[String], +) extends StandardDecisionModel { + + val coveredElements = actors.toSet + val coveredElementRelations = channelsSrcs.zip(channelDsts).toSet + def uniqueIdentifier = "SDFApplication" + +} +``` + +Although this captures the graph part, now we are missing the "labelled" part of it: the data rates. Since SDFs have +fixed production and consumption rates, and they always exist for every channels, we could add to the decision simply via: + +``` +final case class SDFApplication( + val actors: Vector[String], + val channelsSrcs: Vector[String], + val channelsDsts: Vector[String], + val production: Vector[Int], + val consumption: Vector[Int], +) extends StandardDecisionModel { + + val coveredElements = actors.toSet + val coveredElementRelations = channelsSrcs.zip(channelDsts).toSet + def uniqueIdentifier = "SDFApplication" + +} +``` + +which would take care of it. Note that the covered elements have not changed! This does not mean that the decision model created +is wrong, because we added information that is conceptually identified from the same elements and their relations. That is, we "know" +from the model definition that the production and consumption rates are part of the channel definition, and therefore it is not +a problem that new information was added to the decision model _while_ the covered elements and relations remained the same. +A final key elements we are missing is the initial tokens present in each channel. Once more, since we were supposed to start with +this information, it makes sense that no new element is being covered by this decision model extension. + +``` +final case class SDFApplication( + val actors: Vector[String], + val channelsSrcs: Vector[String], + val channelsDsts: Vector[String], + val production: Vector[Int], + val consumption: Vector[Int], + val numInitialTokens: Vector[Int] +) extends StandardDecisionModel { + + val coveredElements = actors.toSet + val coveredElementRelations = channelsSrcs.zip(channelDsts).toSet + def uniqueIdentifier = "SDFApplication" + +} +``` + +And there we have it! The most basic decision model representing SDFs, without taking into consideration execution times, actors sizes etc. +One could checkout the actual decision model for SDFs in `scala-model`: @scaladoc[SDFApplication](idesyde.identification.common.models.sdf.SDFApplication) and see differences. This is because the SDF decision model in the common module also takes into consideration the practical +factors briefly mentioned in order to later perform design space exploration on top of this decision model. + +That's it! This is how one would create a correcy decision model, @scaladoc[StandardDecisionModel](idesyde.identification.common.StandardDecisionModel) specifically, so that it is a expected for the identification procedure. From here, it would now be necessary to define @ref[identification rules](identRules.md) to actually put this decision model to some use. \ No newline at end of file diff --git a/docs/extensions/designModel.md b/docs/extensions_old/designModel.md similarity index 100% rename from docs/extensions/designModel.md rename to docs/extensions_old/designModel.md diff --git a/docs/extensions/identRules.md b/docs/extensions_old/identRules.md similarity index 100% rename from docs/extensions/identRules.md rename to docs/extensions_old/identRules.md diff --git a/docs/extensions/index.md b/docs/extensions_old/index.md similarity index 91% rename from docs/extensions/index.md rename to docs/extensions_old/index.md index de6636c8..de1711cd 100644 --- a/docs/extensions/index.md +++ b/docs/extensions_old/index.md @@ -1,34 +1,34 @@ ---- -layout: default -title: IDeSyDe - Extensions -permalink: /extensions ---- - - -# Extending IDeSyDe - -Since IDeSyDe is built on top of the [Design Space Idenfitication](https://ieeexplore.ieee.org/document/9474082) (DSI) approach, -there are two major entry points for extension in the tool: extending the abstractions that can be solved and extending -the [Model-Driven Engineering (MDE)](https://www.sciencedirect.com/topics/computer-science/model-driven-engineering) frameworks -supported. We note that extending support for another tool does not strictly require this tool to follow any MDE method or use its -framework. Rather, the only necessary thing is that it can fit the DSI idea of a "Design Model". Here's a checklist of up to four -points that might need to be extended to support your particular problem: - -1. If you have tool/tool-suite that is not yet bridged with IDeSyDe, you most likely need to you create a new [DesignModel](idesyde.identification.DesignModel) as outlined [here](designModel), -2. If you have a problem description (think in terms of equations, constraints and their parameters etc) that is not yet in any module within - IDeSyDe, then you need to create one or more [DecisionModel](idesyde.identification.DecisionModel)s - as outlined [here](decisionModel). -3. For some [DecisionModel](idesyde.identification.DecisionModel)s, you might need to create - new [Explorer](idesyde.exploration.Explorer)s in order to actually solve these decision models, i.e. - explore the design space they define. -4. For every new [DecisionModel](idesyde.identification.DecisionModel), you'll likely need to create new identification rules - to identify this decision model and connect to the ones already available. -5. For every new [DesignModel](idesyde.identification.DesignModel), you'll likely need to create new identification rules - _and_ integration rules to identify decision models on top of this design model _and_ retrieve the results back into a format - the original [DesignModel](idesyde.identification.DesignModel) can consume. -6. For every new identification or integration rule created, you need to register it into an existing - [IdentificationModule](idesyde.identification.IdentificationModule) in the IDeSyDe modules or create a new one. - -Then, you are ready to ude IDeSyDe exactly in your situation. All six steps are necessary only if you are starting something from -the very fundamentals, i.e. a new tool suite with a new approach to a new problem with a new algorithm to solve it. With time, -as the open-source and common modules of IDeSyDe grow, less and less of these steps will be necessary for every extension. \ No newline at end of file +--- +layout: default +title: IDeSyDe - Extensions +permalink: /extensions_old +--- + + +# Extending IDeSyDe + +Since IDeSyDe is built on top of the [Design Space Idenfitication](https://ieeexplore.ieee.org/document/9474082) (DSI) approach, +there are two major entry points for extension in the tool: extending the abstractions that can be solved and extending +the [Model-Driven Engineering (MDE)](https://www.sciencedirect.com/topics/computer-science/model-driven-engineering) frameworks +supported. We note that extending support for another tool does not strictly require this tool to follow any MDE method or use its +framework. Rather, the only necessary thing is that it can fit the DSI idea of a "Design Model". Here's a checklist of up to four +points that might need to be extended to support your particular problem: + +1. If you have tool/tool-suite that is not yet bridged with IDeSyDe, you most likely need to you create a new [DesignModel](idesyde.identification.DesignModel) as outlined [here](designModel), +2. If you have a problem description (think in terms of equations, constraints and their parameters etc) that is not yet in any module within + IDeSyDe, then you need to create one or more [DecisionModel](idesyde.identification.DecisionModel)s + as outlined [here](decisionModel). +3. For some [DecisionModel](idesyde.identification.DecisionModel)s, you might need to create + new [Explorer](idesyde.exploration.Explorer)s in order to actually solve these decision models, i.e. + explore the design space they define. +4. For every new [DecisionModel](idesyde.identification.DecisionModel), you'll likely need to create new identification rules + to identify this decision model and connect to the ones already available. +5. For every new [DesignModel](idesyde.identification.DesignModel), you'll likely need to create new identification rules + _and_ integration rules to identify decision models on top of this design model _and_ retrieve the results back into a format + the original [DesignModel](idesyde.identification.DesignModel) can consume. +6. For every new identification or integration rule created, you need to register it into an existing + [IdentificationModule](idesyde.identification.IdentificationModule) in the IDeSyDe modules or create a new one. + +Then, you are ready to ude IDeSyDe exactly in your situation. All six steps are necessary only if you are starting something from +the very fundamentals, i.e. a new tool suite with a new approach to a new problem with a new algorithm to solve it. With time, +as the open-source and common modules of IDeSyDe grow, less and less of these steps will be necessary for every extension. diff --git a/docs/index.md b/docs/index.md index eddaf605..6410e683 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,7 +16,7 @@ and also to situate you about the tool and its methods. * [IDeSyDe key concepts: design space identification and exploration](dsi_dse) * [IDeSyDe overview: software architecture and implementation aspects](overview) * [IDeSyDe formalities: mathematical proofs and other theoretical guarantees](formals) -* IDeSyDe for the experts: extensions +* [IDeSyDe for the experts: extensions](extensions)