doc: dev: Add note about scenarios.

scenarios
Pierre-Antoine Rouby 2024-10-15 15:46:47 +02:00
parent 40d90424a3
commit 5598464081
2 changed files with 1186 additions and 0 deletions

661
doc/dev/scenario.org Normal file
View File

@ -0,0 +1,661 @@
# senario.org -- Pamhyr developers documentation
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
#+STARTUP: indent show2levels
#+INCLUDE: ../tools/macro.org
#+INCLUDE: ../tools/latex.org
#+TITLE: Scenario implementation in Pamhyr2: \textbf{Preparatory work}
#+SUBTITLE: Version: {{{version}}}
#+AUTHOR: {{{INRAE}}}
#+OPTIONS: toc:t
#+LANGUAGE: UKenglish
#+latex: \newpage
* COMMENT tools
#+begin_src emacs-lisp :export none
(add-to-list 'org-structure-template-alist
'("p" "#+begin_src python :python python3 :results output\n\n#+end_src"))
#+end_src
#+RESULTS:
#+begin_example
((p #+begin_src python :python python3 :results output
,#+end_src) (d . #+name: graph-XXX
,#+header: :results drawer
,#+header: :exports results
,#+header: :post attr_wrap(width="12cm", data=*this*, name="graph-XXX", caption="Graph XXX", float="t")
,#+begin_src dot :file "images/graph-XXX.png" :cache no
digraph {
bgcolor="transparent";
node[colorscheme=set19,shape=box,style="filled",fillcolor=9];
}
,#+end_src) (p . src python :python python3 :results output :noweb yes
src) (t . EXPORT latex
\begin{table}
\centering
\resizebox{0.6\linewidth}{!}{
}
%\vspace{0.5pt}
%\caption{Number of tests by errors types}
\end{table}
,#+E) (B . src shell :session *shell* :results output :exports both) (a . export ascii) (c . center) (C . comment) (e . example) (E . export) (h . export html) (l . export latex) (q . quote) (s . src) (v . verse))
#+end_example
#+name: dbg-execute
#+begin_src python :python python3 :results output :noweb yes
def execute(db, query):
print(query)
return db.execute(query)
#+end_src
#+RESULTS: dbg-execute
#+name: execute
#+begin_src python :python python3 :results output :noweb yes
def execute(db, query):
return db.execute(query)
#+end_src
#+RESULTS: execute
* Principe
** Scenario
A scenario is defined by a name, a description and a parent
scenario. If a scenario as no parent, parent value is =None=. So, in
Pamhyr2 the list of scenario must by a tree with a root defined by a
default scenarios with no parent.
#+begin_src sql
CREATE TABLE scenario(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, -- Name of the scenario
description TEXT NOT NULL, -- Rich text description
parent_id INTEGER REFERENCES scenario(id) -- Recursive references
-- for parent scenario
)
#+end_src
** Data
Each data is associated with one and only one scenario. This senario
is defined by the =id=. So, each data structure who can saved in DB
must add the following lines in table définition:
#+begin_src sql
scenario_id INTEGER NOT NULL,
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
#+end_src
To avoid, at least, memory usage exploitation, by default, a scenario
must saved only the modified data from its parent. This contrains
require to wrap any data modification to update the data scenario id
to current scenario id in source code. In addition, we need to modify
the data loading méthode to take in considération this recursive
dependencies.
#+CAPTION: Recursive loading method
#+begin_src python :python python3 :results output :noweb yes
def rec_load(cls, db, current_scenario):
# Default case, end of recursion
if current_scenario is None:
return [] # Default value
table = db.execute(f"<MY SELECT> WHERE scenario_id = {current_scenario}")
# If no data for this scenario, recursion
if len(table) == 0:
parent_id = db.get_parent_id(current_scenario)
return cls.rec_load(db, parent_id)
# Otherelse, parse data and return...
#+end_src
With this method, modify a data in parent scenario, modify this data
in child scenario too. Unless is value has been previously modified in
the child scenario. Deny tree node modification, except for leaf.
This method work, but it dont allow to delete data un child scenarios,
because if we dont found data for this scenario we search for parent
scenario. So, we need a condition to stop recursion in case of data
deletion in child scenario. To stop the recurtion, we can use a dummy
data flag. By default, this flags is =false=, but if this flags is
=true= the data is ignored at loading.
So, we can use this flags for each data structure who can saved in DB:
#+begin_src sql
is_dummy BOOLEAN, -- True if this data as been deleted
#+end_src
Modify the loading method:
#+CAPTION: Recursive loading method with possible dummy data
#+begin_src python :python python3 :results output :noweb yes
def rec_load_2(cls, db, current_scenario):
# Default case, end of recursion
if current_scenario is None:
return [] # Default value
table = db.execute(f"<MY SELECT> WHERE scenario_id = {current_scenario}")
# If no data for this scenario, recursion
if len(table) == 0:
parent_id = db.get_parent_id(current_scenario)
return cls.rec_load(db, parent_id)
for data in table:
if is_dummy(data):
continue
# Otherelse, parse data ...
# return ...
#+end_src
#+RESULTS:
And add a data reduction method:
#+caption: Data reduction method for data subtree
#+begin_src python :python python3 :results output :noweb yes
def reduce_change(self):
# Get the greater scenario
scenar = reduce(
lambda acc, x: max(acc, x._scenario),
self._values,
self._scenario
)
# Apply change on this subtree
self._scenario = scenar
if is_dummy(self): # There are no more subtree
self.values = []
else: # Update data subtree scenario id
for value in self._values:
value.set_scenario(self._scenario)
# Dummy data is no more necessary in this subtree
self._values = list(
filter(
lambda v: not is_dummy(v),
self._values
)
)
# Keep data id unique for all subtree
self.get_new_db_id()
#+end_src
#+RESULTS:
#+latex: \newpage
* Prototype
** Scenario
#+name: scenario
#+begin_src python :python python3 :results output :noweb yes
class Scenario():
def __init__(self, id, name, parent):
self._id = id
self._name = name
self._parent = parent
@classmethod
def create_db(cls, db):
execute(
db, """
CREATE TABLE scenario(
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
parent_id INTEGER REFERENCES scenario(id)
)
"""
)
@classmethod
def load_db(cls, db):
cur = execute(
db, f"SELECT * FROM scenario"
)
table = cur.fetchall()
new = []
for values in table:
new.append(
cls(
values[0], values[1], values[2],
)
)
return new
def save(self, db):
sid = 'NULL' if self._parent is None else self._parent
execute(
db,
"INSERT INTO scenario (id, name, parent_id) " +
f"VALUES ({self._id}, '{self._name}', {sid})"
)
def __repr__(self):
return f"Scenario {{ {self._id}, {self._name}, parent {self._parent} }}"
def __str__(self):
return f"{self._name}({self._id})"
#+end_src
#+RESULTS: scenario
** Data
#+name: data-b
#+begin_src python :python python3 :results output :noweb yes
class B():
def __init__(self, value, scenario):
self._value = value
self._scenario = scenario
self._dummy = False
@classmethod
def create_db(cls, db):
execute(db, """
CREATE TABLE b(
id INTEGER PRIMARY KEY AUTOINCREMENT,
dummy_data BOOLEAN,
x INTEGER,
a_id INTEGER NOT NULL,
scenario_id INTEGER NOT NULL,
FOREIGN KEY(a_id) REFERENCES a(id),
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
)
""")
def save(self, db, a_id):
execute(
db,
"INSERT INTO b (x, dummy_data, a_id, scenario_id) " +
f"VALUES ({self._value}, {self._dummy}, {a_id}, {self._scenario})"
)
@classmethod
def load_db(cls, db, a_id, senar):
if senar is None:
return []
cur = execute(
db,
"SELECT x, scenario_id, dummy_data FROM b " +
f"WHERE scenario_id = {senar} AND a_id = {a_id}"
)
table = cur.fetchall()
if len(table) == 0:
parent = execute(
db,
f"SELECT parent_id FROM scenario WHERE id = {senar}"
).fetchone()
return cls.load_db(db, parent[0])
new = []
for values in table:
if values[2]: # Is dummy
continue
new.append(cls(values[0], values[1]))
return new
def set_value(self, value, scenario):
self._value = value
self._scenario = scenario
def set_dummy(self, scenario):
self._scenario = scenario
self._dummy = True
def __repr__(self):
if self._dummy:
return ""
return f"{self._value}"
def __str__(self):
if self._dummy:
return ""
return f"{self._value}"
#+end_src
#+RESULTS: data-b
#+name: data-a
#+begin_src python :python python3 :results output :noweb yes
class A():
def __init__(self, id, values, scenario):
self._id = id
self._values = values
self._scenario = scenario
self._dummy = False
@classmethod
def create_db(cls, db):
execute(db, """
CREATE TABLE a(
id INTEGER PRIMARY KEY,
dummy_data BOOLEAN,
scenario_id INTEGER,
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
)
""")
def save(self, db):
self.reduce_change()
execute(db, f"DELETE FROM a WHERE scenario_id = {self._scenario}")
execute(
db,
"INSERT INTO a (id, dummy_data, scenario_id) " +
f"VALUES ({self._id}, {self._dummy}, {self._scenario})"
)
execute(
db,
"DELETE FROM b " +
f"WHERE scenario_id = {self._scenario} " +
f"AND a_id = {self._id}"
)
for value in self._values:
value.save(db, self._id)
def reduce_change(self):
diff_scenar = reduce(
lambda acc, x: max(acc, x._scenario),
self._values,
self._scenario
)
print(f" ~> Reduce: {self._scenario} to {diff_scenar}")
self._scenario = diff_scenar
# Reduce new scenario value on each value
for value in self._values:
value._scenario = self._scenario
# Delete useless dummy data
self._values = list(
filter(
lambda v: not v._dummy,
self._values
)
)
# HACK: keep id unique
self._id = self._id * 100 + diff_scenar
@classmethod
def load_db(cls, db, senar):
if senar is None:
return []
cur = execute(
db,
f"SELECT id, scenario_id, dummy_data FROM a WHERE scenario_id = {senar}"
)
table = cur.fetchall()
if len(table) == 0:
parent = execute(
db,
f"SELECT parent_id FROM scenario WHERE id = {senar}"
).fetchone()
return cls.load_db(db, parent[0])
new = []
for values in table:
if values[2]:
continue
bb = B.load_db(db, values[0], senar)
new.append(cls(values[0], bb, values[1]))
return new
def set_dummy(self, scenario):
self._scenario = scenario
self._dummy = True
def add(self, b):
self._values.append(b)
def delete(self, index, scenario):
self._values[index].set_dummy(scenario)
self._scenario = scenario
def __repr__(self):
if self._dummy:
return "{ }"
return f"{{ {self._values}, ({self._scenario}) }}"
def __str__(self):
if self._dummy:
return "{ }"
return f"{{ {list(map(str, self._values))}, ({self._scenario}) }}"
#+end_src
#+RESULTS: data-a
** Full prototype
#+begin_src python :python python3 :results output :exports both :noweb yes :cache yes
from functools import reduce
def execute(db, query):
# print(query)
return db.execute(query)
def get_tree(db):
from treelib import Node, Tree
tree = Tree()
for senar in db.execute("SELECT * FROM scenario").fetchall():
if senar[1] is None:
tree.create_node(
str(Scenario(senar[0], senar[1], senar[2])) +
" : " + str(A.load_db(db, senar[0])[0]),
senar[0]
)
else:
tree.create_node(
str(Scenario(senar[0], senar[1], senar[2])) +
" : " + str(A.load_db(db, senar[0])[0]),
senar[0],
parent=senar[2]
)
return tree
### --- Scenario ---
<<scenario>>
### --- class B ---
<<data-b>>
### --- class A ---
<<data-a>>
### --- Script ---
import sqlite3
import pprint
pp = pprint.PrettyPrinter(width=79, compact=True, depth=6)
with sqlite3.connect(":memory:") as db:
cur = db.cursor()
Scenario.create_db(cur)
A.create_db(cur)
B.create_db(cur)
print("--- Default scenario (s0) ---")
# One scenario
s0 = Scenario(0, "s0", None)
a0 = A(
1,
[
B(0, s0._id),
B(1, s0._id),
B(2, s0._id),
],
s0._id
)
s0.save(cur)
a0.save(cur)
print("--- New scenario (s1) -- copy without modification ---")
# New scenario
s1 = Scenario(1, "s1", s0._id)
s1.save(cur)
print("--- New scenario (s2) -- data modification ---")
# New scenario 2 with data
s2 = Scenario(2, "s2", s0._id)
s2.save(cur)
a2 = a0
bb = list(map(
lambda b: b.set_value(b._value + 1, s2._id),
a2._values
))
a2.save(cur)
print("--- New scenario (s3) -- delete data ---")
# New scenario 3 with data
s3 = Scenario(3, "s3", s0._id)
s3.save(cur)
a3 = A.load_db(cur, s3._id)[0]
a3._values[0].set_dummy(s3._id)
a3.save(cur)
print("--- New scenario (s4) -- new data ---")
s4 = Scenario(4, "s4", s3._id)
s4.save(cur)
a4 = A.load_db(cur, s3._id)[0]
a4.add(B(666, s4._id))
a4.save(cur)
print("--- Scenario tree ---")
tree = get_tree(db)
print(tree)
print("--- Modify s0 data ---")
aa = A.load_db(db, s0._id)[0]
bb = list(map(
lambda b: b.set_value(b._value * 100 - 1, s0._id),
aa._values
))
aa.save(db)
print("--- Scenario tree ---")
tree = get_tree(db)
print(tree)
print("--- DB ---")
ss = db.execute("SELECT * FROM scenario").fetchall()
print(f"+ scenario ({len(ss)}):")
pp.pprint(ss)
aa = db.execute("SELECT * FROM a").fetchall()
print(f"+ a ({len(aa)}):")
pp.pprint(aa)
bb = db.execute("SELECT * FROM b").fetchall()
print(f"+ b ({len(bb)}):")
pp.pprint(bb)
#+end_src
#+RESULTS[96c84f23be557425ae2822ef7f174175ef69f9b9]:
#+begin_example
--- Default scenario (s0) ---
~> Reduce: 0 to 0
--- New scenario (s1) -- copy without modification ---
--- New scenario (s2) -- data modification ---
~> Reduce: 0 to 2
--- New scenario (s3) -- delete data ---
~> Reduce: 0 to 3
--- New scenario (s4) -- new data ---
~> Reduce: 3 to 4
--- Scenario tree ---
s0(0) : { ['0', '1', '2'], (0) }
├── s1(1) : { ['0', '1', '2'], (0) }
├── s2(2) : { ['1', '2', '3'], (2) }
└── s3(3) : { ['1', '2'], (3) }
└── s4(4) : { ['1', '2', '666'], (4) }
--- Modify s0 data ---
~> Reduce: 0 to 0
--- Scenario tree ---
s0(0) : { ['-1', '99', '199'], (0) }
├── s1(1) : { ['-1', '99', '199'], (0) }
├── s2(2) : { ['1', '2', '3'], (2) }
└── s3(3) : { ['1', '2'], (3) }
└── s4(4) : { ['1', '2', '666'], (4) }
--- DB ---
+ scenario (5):
[(0, 's0', None), (1, 's1', 0), (2, 's2', 0), (3, 's3', 0), (4, 's4', 3)]
+ a (4):
[(10000, 0, 0), (10002, 0, 2), (10003, 0, 3), (1000304, 0, 4)]
+ b (14):
[(1, 0, 0, 100, 0), (2, 0, 1, 100, 0), (3, 0, 2, 100, 0), (4, 0, 1, 10002, 2),
(5, 0, 2, 10002, 2), (6, 0, 3, 10002, 2), (7, 0, 1, 10003, 3),
(8, 0, 2, 10003, 3), (9, 0, 1, 1000304, 4), (10, 0, 2, 1000304, 4),
(11, 0, 666, 1000304, 4), (12, 0, -1, 10000, 0), (13, 0, 99, 10000, 0),
(14, 0, 199, 10000, 0)]
#+end_example

View File

@ -0,0 +1,525 @@
# presentation.org -- Pamhyr
# Copyright (C) 2023 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
#+STARTUP: indent hideblocks content beamer
#+TITLE: \textbf{Pamhyr2}
#+SUBTITLE: Scenarios managements
# #+AUTHOR: Pierre-Antoine Rouby
#+LATEX_HEADER: \author[Pierre-Antoine Rouby]{\textbf{Pierre-Antoine Rouby}}
#+EMAIL: pierre-antoine.rouby@inrae.fr
#+INSTITUTE: INRAE Lyon-Villerbanne, teams River Hydraulics
#+LATEX_HEADER: \institute{INRAE Lyon-Villerbanne, River Hydraulics team}
#+DATE: 9th November
#+KEYWORDS: g ui, hydraulics, sedimentary, hydro-sedimentary, 1D modelling, freesoftware, foss
#+OPTIONS: H:2 toc:t num:t author:nil
#+LATEX_CLASS: beamer
#+LATEX_CLASS_OPTIONS: [slideopt,A4,showboxes,svgnames,aspectratio=169]
# #+LATEX_CLASS_OPTIONS: [presentation]
#+BEAMER_THEME: default
#+COLUMNS: %45ITEM %10BEAMER_ENV(Env) %10BEAMER_ACT(Act) %4BEAMER_COL(Col)
#+LANGUAGE: fr
#+LATEX_HEADER: \usepackage[frenchb]{babel}
#+BEGIN_SRC emacs-lisp :results silent :exports none
(setq org-latex-pdf-process (list
"latexmk -pdflatex='lualatex -shell-escape -interaction nonstopmode' -pdf -f %f"))
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-latex-listings 'minted)
(setq org-src-fontify-natively t)
(org-add-link-type
"cite" 'ebib
(lambda (path desc format)
(cond
((eq format 'html)
(format "(<cite>%s</cite>)" path))
((eq format 'text)
(format "[%s]" path))
((eq format 'latex)
(if (or (not desc) (equal 0 (search "cite:" desc)))
(format "\\cite{%s}" path)
(format "\\cite[%s][%s]{%s}"
(cadr (split-string desc ";"))
(car (split-string desc ";")) path))))))
#+END_SRC
# Wrapper
#+NAME: attr_wrap
#+HEADER: :var width="\\textwidth"
#+HEADER: :var caption=""
#+HEADER: :var smallcaption=""
#+HEADER: :var name=""
#+HEADER: :var data=""
#+HEADER: :var float="nil"
#+BEGIN_SRC sh :results output :exports none
echo "#+CAPTION[$smallcaption]: $caption"
echo "#+NAME: $name"
echo "#+ATTR_LATEX: :width $width :float $float"
echo "$data"
#+END_SRC
#+LATEX_HEADER: \setbeamertemplate{footline}[frame number]
#+LATEX_HEADER: \setbeamertemplate{headline}{}
#+LATEX_HEADER: \usepackage{multirow}
#+LATEX_HEADER: \usepackage{fontawesome5}
#+LATEX_HEADER: \usepackage{tcolorbox}
#+LATEX_HEADER: \usepackage{tikz}
#+LATEX_HEADER: \logo{\includegraphics[width=.1\textwidth]{../../../src/View/ui/ressources/Logo-INRAE.png}}
#+LATEX_HEADER: \newcommand{\R}[1]{\rotatebox[origin=c]{90}{#1}}
# Beamer colors
#+LATEX_HEADER: \setbeamersize{text margin left=0.5cm,text margin right=0.5cm}
#+LATEX_HEADER: \setbeamerfont{alerted text}{series=\bfseries}
#+LATEX_HEADER: \setbeamerfont{example text}{series=\bfseries}
#+LATEX_HEADER: \definecolor{inrae_1}{RGB}{102,193,191}
#+LATEX_HEADER: \definecolor{inrae_2}{RGB}{0,150,152}
#+LATEX_HEADER: \definecolor{inrae_3}{RGB}{39,86,98}
#+LATEX_HEADER: \setbeamercolor{alerted text}{fg=inrae_1}
#+LATEX_HEADER: \setbeamercolor{structure}{fg=inrae_2}
#+LATEX_HEADER: \setbeamercolor{normal text}{fg=inrae_3}
#+LATEX_HEADER: \setbeamercolor*{author}{fg=inrae_3}
#+LATEX_HEADER: \usepackage[absolute,showboxes,overlay]{textpos}
#+LATEX_HEADER: \TPshowboxesfalse
#+LATEX_HEADER: \textblockorigin{5mm}{0mm}
# Biblio
#+LATEX_HEADER: \usepackage{natbib}
# #+LATEX_HEADER: \bibliographystyle{apalike}
#+LATEX_HEADER: \setbeamertemplate{bibliography item}{}
#+LATEX_HEADER: \renewcommand\bibfont{\scriptsize}
#+LATEX_HEADER: \setbeamertemplate{frametitle continuation}[from second]
#+LATEX_HEADER: \setbeamercolor*{bibliography entry title}{fg=inrae_3}
#+LATEX_HEADER: \setbeamercolor*{bibliography entry author}{fg=inrae_3}
#+LATEX_HEADER: \setbeamercolor*{bibliography entry location}{fg=inrae_3}
#+LATEX_HEADER: \usepackage{bbding}
#+LATEX_HEADER: \usepackage{pdfpages}
# Renew title page
#+LATEX_HEADER: \defbeamertemplate*{title page}{customized}[1][]
#+LATEX_HEADER: {
# #+LATEX_HEADER: {
# #+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}
# #+LATEX_HEADER: \tikz[overlay,remember picture]
# #+LATEX_HEADER: \node[xshift=-1cm,yshift=-1cm,text width=10cm] at (current page.north east) {
# #+LATEX_HEADER: 7$^{th}$ International Conference\\
# #+LATEX_HEADER: 8TH-10TH November\\
# #+LATEX_HEADER: EDF Lab - CHATOU, FRANCE
# #+LATEX_HEADER: }
# #+LATEX_HEADER: }
#+LATEX_HEADER: {
#+LATEX_HEADER: \usebeamerfont{title}\inserttitle\par
#+LATEX_HEADER: \usebeamerfont{title}\usebeamercolor[fg]{title}
#+LATEX_HEADER: }
#+LATEX_HEADER: \bigskip
#+LATEX_HEADER: \begin{center}
#+LATEX_HEADER: \usebeamerfont{subtitle}\usebeamercolor[fg]{subtitle}
#+LATEX_HEADER: {
#+LATEX_HEADER: \LARGE\insertsubtitle\par
#+LATEX_HEADER: }
#+LATEX_HEADER: \bigskip
#+LATEX_HEADER: \usebeamerfont{author}\usebeamercolor[fg]{author}\insertauthor\par
#+LATEX_HEADER: \bigskip
#+LATEX_HEADER: \usebeamerfont{institute}\usebeamercolor[fg]{institute}\insertinstitute\par
#+LATEX_HEADER: \bigskip
#+LATEX_HEADER: \usebeamerfont{date}\usebeamercolor[fg]{date}\insertdate\par
#+LATEX_HEADER: \usebeamercolor[fg]{titlegraphic}\inserttitlegraphic
#+LATEX_HEADER: \end{center}
#+LATEX_HEADER: }
# #+LATEX_HEADER: \newcommand{\tred}[1]{\textcolor{rouge_inrae}{#1}}
#+TODO: TODO WIP TOREVIEW | DONE
#+MACRO: pamhyr \textsc{PAMHyR}
#+MACRO: pamhyr2 \textsc{Pamhyr2}
#+MACRO: pause \pause
#+MACRO: framebreak \framebreak
#+MACRO: no
# #+MACRO: OK \checkmark
#+MACRO: OK \faIcon{check}
#+MACRO: bf \textbf{$1}
# #+latex: \frame{\tocpage}
* Problématique
** Problématique
*** Utilisateur
- Définire une version modifier de l'étude (changement dans les
données)
- Comparé des résultats entre une variante et l'étude
{{{pause}}}
**** COMMENT Développeur
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
- Un unique fichier
- Limité la duplication de donnée à sauvegarder
- Garder une bonne cohérence entre données et résultats
{{{pause}}}
*** Scénarios
:PROPERTIES:
:BEAMER_COL: 1
:BEAMER_ENV: definition
:END:
Un scénario est une variate d'une étude.
** Problématique -- Avancer
*** Utilisateur
- Définire une version modifier d'un senarios
- Comparé des résultats entre plusieurs senarios
{{{pause}}}
**** COMMENT Développeur
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
- Un unique fichier
- Limité la duplication de donnée à sauvegarder
- Garder une bonne cohérence entre données et résultats
{{{pause}}}
*** Scénarios
:PROPERTIES:
:BEAMER_COL: 1
:BEAMER_ENV: definition
:END:
Un scénario peut être l'étude ou une variate d'un autre scénario.
** Problématique -- Encore plus avancer
*** Utilisateur
- Définire un ensemble fini de variante correspondant a un ensemble de
valeur pour un(des) paramètre(s) et executer un solveur sur
l'ensemble des variantes
- Pouvoir comparé des metrics sur un ensemble de résultats trop grand
pour une comparaisont à la mains
{{{pause}}}
**** COMMENT Développeur
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
- Un unique fichier
- Limité la duplication de donnée à sauvegarder
- Garder une bonne cohérence entre données et résultats
{{{pause}}}
*** Scénarios
:PROPERTIES:
:BEAMER_COL: 1
:BEAMER_ENV: definition
:END:
Un scénario peut être l'étude, une variate d'un scénarios ou un
ensemble fini de variantes d'un scénarios.
** Problématique -- Encore plus plus avancer
*** Utilisateur
- Définire un ensemble fini de variante correspondant a un ensemble de
valeur pour un(des) paramètre(s) et faire un nombre fini de tirage
aléatoire dans ces paramètre pour executer un solveur ces paramètres
- Pouvoir comparé des metrics sur un ensemble de résultats trop grand
pour une comparaisont à la mains
{{{pause}}}
*** Scénarios
:PROPERTIES:
:BEAMER_COL: 1
:BEAMER_ENV: definition
:END:
Un scénario peut être l'étude, une variate d'un scénarios ou un
ensemble fini ou un tirage aléatoire dans un ensemble de variantes
d'un scénarios.
** Problématique -- Développeur
*** Développeur
- Permetre a l'utilisateur de *garder une bonne cohérence entre
données et résultats* de façon claire
- Permetre a l'utilisateur de *géré les scénarios* de façon claire
(représentation graphique)
- Garder *un unique fichier* (=.pamhyr=)
- *Limité la duplication* de donnée à sauvegarder
- Permetre à l'utilisateur de garder les *résultats pertinant* sans
exploser la mémoire de l'ordinateur
* Proposition
** Proposition -- Concept
*** {{{no}}}
\vspace{-1.2cm}
**** Deux type de scénarios
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
- Scénarios simple
- Scénarios d'éxecution d'ensemble
{{{pause}}}
**** Scénarios simple
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
Est composer:
- d'un identifiant unique
- d'un nom (définie par l'utilisateur)
- d'une description (définie par l'utilisateur)
- d'un parent (définie par l'utilisateur)
{{{pause}}}
\vspace{-0.5cm}
*** Scénarios d'ensembles
**** {{{no}}}
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
\vspace{-1cm}
Est composer:
- d'un identifiant unique
- d'un nom (définie par l'utilisateur)
- d'une description (définie par l'utilisateur)
- d'un parent (définie par l'utilisateur)
- d'un ou plusieurs ensemble de valeur
**** {{{no}}}
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
\vspace{-0.5cm}
Un ensemble de valeurs est definie par:
- une valeurs de départ
- une valeurs de fin
- un pas de valeur
- un élément d'origine (élément définie dans l'étude)
- une fonctions (modification de l'élément à l'aide d'une valeur de
l'ensemble)
** Proposition -- Limitation
*** Scénarios simple
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
Si le scénarios est le *parent d'un autre scénarios*, il ne *peut plus
être modifier* sans risquer des comportement difficilement
comprehensible pour l'utilisateur.
{{{pause}}}
*** Scénarios d'ensembles
:PROPERTIES:
:BEAMER_COL: 0.5
:BEAMER_ENV: block
:END:
- Un scénarios d'ensemble *ne peut pas être parent* d'un autre
scénarios
- Le nombre d'exécution peut très rapidement grossir
** Proposition -- Affichage
#+name: graph-scenarios
#+header: :results drawer
#+header: :exports results
#+header: :post attr_wrap(width="7cm", data=*this*, name="graph-scenarios", caption="Exemple of scenarios graph", float="t")
#+begin_src dot :file "images/graph-scenarios.png" :cache no
digraph {
bgcolor="transparent";
node[colorscheme=pastel19,shape=ellipse,style="filled",fillcolor=9];
b[fillcolor=2];
aa[shape=box,fillcolor=2];
aa2[label="aa'", shape=box, fillcolor=2];
ad[shape=box, fillcolor=2];
re[shape=box, fillcolor=2];
rf[shape=box, fillcolor=2];
default -> a;
default -> b;
default -> c;
a -> aa;
a -> aa2;
a -> f -> rf;
c -> d -> ad;
c -> e -> re;
}
#+end_src
#+RESULTS[80ed2484b9cc71143f800ff23c10846fd04697c3]: graph-scenarios
:results:
#+CAPTION[]: Exemple of scenarios graph
#+NAME: graph-scenarios
#+ATTR_LATEX: :width 7cm :float t
[[file:images/graph-scenarios.png]]
:end:
* Solution technique
** Technique -- scénarios
#+begin_src sql
CREATE TABLE scenario(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, -- Name of the scenario
description TEXT NOT NULL, -- Rich text description
parent_id INTEGER REFERENCES scenario(id) -- Recursive references
-- for parent scenario
)
#+end_src
** Technique -- Données -- Enregistrement
#+begin_src sql
-- Unique ID (Must be unused, to delete)
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
-- New ID (not unique)
pamhyr_id INTEGER NOT NULL,
-- (Optional) Flag for set there is no data in this scenario and
-- ignore parent scenario
dummy BOOLEAN NOT NULL,
-- Corresponding scenario
scenario_id INTEGER NOT NULL,
PRIMARY KEY(pamhyr_id, scenario_id),
FOREIGN KEY(scenario_id) REFERENCES scenario(id),
#+end_src
** Technique -- Données -- Chargement
#+begin_src python :python python3 :results output :noweb yes
def load(cls, db, current_scenario):
# Default case, end of recursion
if current_scenario is None:
return [] # Default value
table = db.execute(f"<MY SELECT> WHERE scenario_id = {current_scenario}")
# If no data for this scenario, recursion
if len(table) == 0:
parent_id = db.get_parent_id(current_scenario)
return cls.load(db, parent_id)
# Otherelse, parse data and return...
#+end_src
** Technique -- Données -- Modification
#+begin_src python :python python3 :results output :noweb yes
def set_modified(self, current_scenario):
self.scenario = current_scenario
#+end_src
#+begin_src python :python python3 :results output :noweb yes
def delete(self, current_scenario):
self.deleted = True
self.set_modified(current_scenario)
#+end_src
** Technique -- Exécution d'ensemble
#+begin_src sql
CREATE TABLE range_set(
id INTEGER PRIMARY KEY AUTOINCREMENT,
start REAL NOT NULL, -- Range start
end REAL NOT NULL, -- Range end
step REAL NOT NULL, -- Range step
generator_name TEXT NOT NULL, -- Generator function name (ex:
-- 'minor_strickler')
original_data_id INTEGER, -- (optional) Ref to data who apply
-- this range (ex: a strickler id)
scenario_id INTEGER NOT NULL,
FOREIGN KEY(scenario_id) REFERENCES scenario(id)
)
#+end_src
* Sauvegarde des résultats
** Sauvegarde des résultats
*** Scénarios simple
Sauvegarde d'un seul résultats complet par scénarios (et par solver).
*** Scénarios d'ensemble
Sauvegarde de metrics récupéré sur un ensemble de résultats (pas de
sauvegarde de tous les résultats) ou certain résultats particuliers.
* Question & remarque
** Question & remarque
- Solution satisfaisante ?
- Cas d'usage intéressent non couvert ?
- Contre exemple ?
- Meilleur solution ?