diff --git a/doc/userdoc.org b/doc/userdoc.org index d9d7407109d839425e8cb1040973980055321356..b58c69765189573fa13384b936750733ff114bc6 100644 --- a/doc/userdoc.org +++ b/doc/userdoc.org @@ -1,4 +1,4 @@ -#+SETUPFILE: ../packages/org-themes/src/bigblow_inline/bigblow_inline.theme +#+SETUPFILE: ../packages/org-themes/src/readtheorg_inline/readtheorg_inline.theme #+STARTUP: org-pretty-entities entitiespretty #+PROPERTY: header-args :comments no @@ -15,6 +15,8 @@ #+HTML_HEAD_EXTRA: <style> .remark{ @extend .todo !optional;} </style> #+LATEX_CLASS_OPTIONS: [10pt] #+LATEX_HEADER: \usepackage[hmargin=2.5cm,vmargin=1.5cm]{geometry} +#+LATEX_HEADER: \usepackage{ae,lmodern} +#+LATEX_HEADER: \usepackage[OT1]{fontenc} #+LATEX_COMPILER: pdflatex --shell-escape #+LATEX_HEADER_EXTRA: \usepackage{amsmath} @@ -37,8 +39,7 @@ ~pugs~[fn:pugs-def] is a general purpose solver collection built to approximate solutions of partial differential equations. It is mainly -(but not only) designed to deal with hyperbolic problems using -finite-volume methods. +(but not only) designed to deal with finite-volume methods. ~pugs~ is a parallel software that uses ~MPI~[fn:MPI-def] and multi-threading for parallelism. Multi-threading is achieved through an encapsulation @@ -50,8 +51,7 @@ close to the mathematics) to build more complex solvers. This approach is inspired by the success of [[http://freefem.org][FreeFEM]], which use a similar approach. Before detailing the leading concepts and choices that we have made to -develop ~pugs~, we give a simple example that should illustrate the -capabilities of the code. +develop ~pugs~, we give a simple example. ** An example For instance, the following code builds a uniform Cartesian grid of @@ -276,28 +276,22 @@ common utilities are available directly in scripts. ~pugs~ is a research oriented software, thus generally the user is also a developer. If this paragraph is indeed more dedicated to the developer, by reading it, the user will have a better understanding of -the development choices and the underlying policy that that the code +the development choices and the underlying policy that the code follows. Actually the development framework imposed by the DSL tends to guide writing of new methods. -- A natural consequence is that the developer is encourage to write - small independent ~C++~ methods (even if it does not forbid to write - big monolithic pieces of code). However as already said, one should - try to respect the following precept: write small piece of code to - ease their testing and validation, try to do simple things the right - way. -- Also, in the process of writing a *new numerical methods*, one must - create *new functions in the language*. Moreover, if a new method is - close to an existing one, it is generally *better* to use completely - new underlying ~C++~ code than to patch existing methods. Starting - from a *copy* of the existing code ~C++~ is *encouraged* for - developments. This may sound weird since classical development - guidelines encourage inheritance or early redesign. Actually, this - policy is the result of the following discussion. +- In the process of writing a *new numerical methods*, one must create + *new functions in the language*. Moreover, if a new method is close to + an existing one, it is generally *better* to use completely new + underlying ~C++~ code than to patch existing methods. Starting from a + *copy* of the existing code ~C++~ is *encouraged* for developments. This + may sound weird since classical development guidelines encourage + inheritance or early redesign. Actually, this policy is the result + of the following discussion. - Using this approach, one *separates* clearly the *design* of a - numerical method and the *design* of the code! + numerical method and the *design* of the code. - From the computer science point of view, early design for new numerical methods is generally wrong: usually one cannot anticipate precisely enough eventual problems or method @@ -368,12 +362,12 @@ generally the implementation itself. It is even more true when the developer feels that changes to the code are natural and that the modifications themselves look easy. Obviously, any experienced programmer knows that writing the code is only the first step of a -much longer process which requires rigorous tests and validations, the -enrichment of a non-regression database. Generally one also desires to -ensure that the development is used within the correct bounds which +much longer process which requires rigorous tests and validations (the +enrichment of a non-regression database). Generally one also desires +to ensure that the development is used within the correct bounds which requires to implement data verification. In a perfect world, an up-to-date documentation of the functionality and its domain of -validity. +validity should be provided. This is even more true when defining a language (or a DSL). Enriching a language syntax (or grammar) is not something that must be done to @@ -391,7 +385,7 @@ integrate low-level instructions. Low-level instructions give too much freedom and thus are a source of errors. Several things are already done to forbid this kind of evolution. The constness of high-level data is a good illustration. For instance, meshes or discrete -functions *cannot* be modified. This is not only a security to protects +functions *cannot* be modified. This is not only a security to protect the user from doing "dangerous" manipulations, but it also permits to define high-level optimizations. - Since meshes are constant objects, one can for instance compute @@ -517,11 +511,11 @@ produces the following compilation error #+results: uninitialized-variable For more complex constructions, it can be very difficult to detect it -at /compile time/, this is why it is *encourage* to use variable +at /compile time/, this is why it is *encouraged* to use variable definition (see [[definition-simple-variables]]). -Observe nonetheless, ~pugs~ checks at /run time/ that used variables are -correctly defined. If not an error is produced. +Observe nonetheless that ~pugs~ checks at /run time/ that used variables +are correctly defined. If not an error is produced. #+END_warning **** Definition of simple variables<<definition-simple-variables>> @@ -742,7 +736,7 @@ Here is a table of implicit type conversions *when allowed*. | ~N~ | ~B~, ~Z~ | | ~Z~ | ~B~, ~N~ | | ~R~ | ~B~, ~N~, ~Z~ | -| ~R^1~ | ~B~, ~N~, ~Z~, ~R~, ~0~ (special value) | +| ~R^1~ | ~B~, ~N~, ~Z~, ~R~ | | ~R^2~ | ~0~ (special value) | | ~R^3~ | ~0~ (special value) | | ~R^1x1~ | ~B~, ~N~, ~Z~, ~R~, ~0~ (special value) | @@ -1171,73 +1165,27 @@ temporary. One will see bellow that one can write ~A = A*B;~ if needed. - ~N~: natural integer ($\mathbb{N}$ or $\mathbb{Z}_{\ge0}$) left hand side variable. | ~/=~ allowed expression type | |----------------------------| - | ~B~ | | ~N~ | | ~Z~ (for convenience) | - ~Z~: integer ($\mathbb{Z}$) left hand side variable. | ~/=~ allowed expression type | |----------------------------| - | ~B~ | | ~N~ | | ~Z~ | - ~R~: real ($\mathbb{R}$) left hand side variable. | ~/=~ allowed expression type | |----------------------------| - | ~B~ | | ~N~ | | ~Z~ | | ~R~ | -- ~R^1~: vector of dimension 1 ($\mathbb{R}^1$) left hand side variable. - | ~/=~ allowed expression type | - |----------------------------| - | ~B~ | - | ~N~ | - | ~Z~ | - | ~R~ | - -- ~R^2~: vector of dimension 2 ($\mathbb{R}^2$) left hand side variable. - | ~/=~ allowed expression type | - |----------------------------| - | ~B~ | - | ~N~ | - | ~Z~ | - | ~R~ | - -- ~R^3~: vector of dimension 3 ($\mathbb{R}^3$) left hand side variable. - | ~/=~ allowed expression type | - |----------------------------| - | ~B~ | - | ~N~ | - | ~Z~ | - | ~R~ | - -- ~R^1x1~: matrix of dimensions $1\times1$ ($\mathbb{R}^{1\times1}$) left hand side variable. - | ~/=~ allowed expression type | - |----------------------------| - | ~B~ | - | ~N~ | - | ~Z~ | - | ~R~ | - -- ~R^2x2~: matrix of dimension $2\times2$ ($\mathbb{R}^{2\times2}$) left hand side variable. - | ~/=~ allowed expression type | - |----------------------------| - | ~B~ | - | ~N~ | - | ~Z~ | - | ~R~ | - -- ~R^3x3~: matrix of dimension $3\times3$ ($\mathbb{R}^{3\times3}$) left hand side variable. - | ~/=~ allowed expression type | - |----------------------------| - | ~B~ | - | ~N~ | - | ~Z~ | - | ~R~ | +- ~R^d~: the ~/=~ operator is not defined for left hand side vector (of + dimension $d\in\{1,2,3\}$) variables. +- ~R^dxd~: the ~/=~ operator is not defined for left hand side matrix (of + dimension $d\times d$ with $d\in\{1,2,3\}$) variables. **** Unary operators @@ -1317,15 +1265,15 @@ Here is the list of binary operators | keyword | operator | |---------+-----------------------| | ~and~ | logic and | -| ~or~ | logic and | +| ~or~ | logic or | | ~xor~ | logic exclusive or | |---------+-----------------------| | ~==~ | equality | | ~!=~ | non-equality | | ~<~ | lower than | -| ~<=~ | lower than or equal | +| ~<=~ | lower or equal than | | ~>~ | greater than | -| ~>=~ | greater than or equal | +| ~>=~ | greater or equal than | |---------+-----------------------| | ~<<~ | shift left | | ~>>~ | shift right | @@ -1419,12 +1367,20 @@ they follow a few rules. \left| \begin{array}{rl} \mathtt{+}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{N}\\ - \mathtt{*}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{N}\\ - \mathtt{/}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{N} + \mathtt{*}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{N} \end{array} \right. \end{equation*} #+end_src + Boolean values (type ~B~) are not allowed as the right operand of a + division. + #+begin_src latex :results drawer :exports results + \begin{equation*} + \forall \mathbb{S} \in \{\mathbb{B},\mathbb{N}\}, + \mathtt{/}: \mathbb{S} \times \mathbb{N} \to \mathbb{N} + \end{equation*} + #+end_src + Observe that ~-~ is *not* in the list. - Operators that return an integer ~Z~. @@ -1443,6 +1399,15 @@ they follow a few rules. \right. \end{equation*} #+end_src + The divide operator does not allow boolean values as a right + operand. + #+begin_src latex :results drawer :exports results + \begin{align*} + \forall \mathbb{S}_1 \in \{\mathbb{B},\mathbb{N},\mathbb{Z}\}&\mbox{ and } \mathbb{S}_2 \in \{\mathbb{N},\mathbb{Z}\}, + \mbox{ such that }\mathbb{S}_1 = \mathbb{Z}\mbox{ or }\mathbb{S}_2 = \mathbb{Z},\\ + &\mathtt{/}: \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{Z}. + \end{align*} + #+end_src Finally the following operator is also defined #+begin_src latex :results drawer :exports results \begin{equation*} @@ -1461,12 +1426,20 @@ they follow a few rules. \begin{array}{rl} \mathtt{+}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{R}\\ \mathtt{-}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{R}\\ - \mathtt{*}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{R}\\ - \mathtt{/}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{R} + \mathtt{*}:& \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{R} \end{array} \right. \end{equation*} #+end_src + The divide operator does not allow boolean values as a right + operand. + #+begin_src latex :results drawer :exports results + \begin{align*} + \forall \mathbb{S}_1 \in \{\mathbb{B},\mathbb{N},\mathbb{Z},\mathbb{R}\}&\mbox{ and } \mathbb{S}_2 \in \{\mathbb{N},\mathbb{Z},\mathbb{R}\}, + \mbox{ such that }\mathbb{S}_1 = \mathbb{R}\mbox{ or }\mathbb{S}_2 = \mathbb{R},\\ + &\mathtt{/}: \mathbb{S}_1 \times \mathbb{S}_2 \to \mathbb{Z}. + \end{align*} + #+end_src - Operators that return a small vector ~R^d~. #+begin_src latex :results drawer :exports results @@ -1523,7 +1496,7 @@ they follow a few rules. **** Operator precedence and associativity -To avoid confusions, the operators precedence in ~pugs~ language follow +To avoid confusions, the operators precedence in ~pugs~ language follows the same rules as in ~C++~. This is summarized in the following table, where ~a~ and ~b~ denotes two @@ -1640,20 +1613,22 @@ illustrate this, let us consider the following example. In this example, we are dealing with 3 ~mesh~ variables. - First, ~m1~ is defined as a uniform cartesian mesh in dimension 2 of - $]0,1[^2$ made of $10\times10$ identical square cells. -- Then ~m2~ is a copy of the variable ~m1~. It is a copy of the variable, - but the underlying mesh is *the same*! There is no duplication of the - mesh in memory. -- Then, the mesh variable ~m3~ is *defined* to refer to a *new* mesh. It is - /similar/ to the mesh contained in ~m1~ and ~m2~, but it is *not* the same - one! When ~m3~ is defined two meshes, (and two connectivities) are - resident in memory. One of the mesh is referred by either ~m1~ or ~m2~ - and the other one is referred by ~m3~. -- Finally, the last instruction (~m3 = m1;~) sets ~m3~ to also refer the - mesh referred by ~m1~ and ~m2~. Since no other variable refers to its - former mesh, the mesh is destroyed (memory is freed). At the end of - the program, all the variables ~m1~, ~m2~ and ~m3~ are referring to the - same mesh, and there is only one mesh that resides in memory. + $]0,1[^2$ made of $10\times10$ identical square cells. Let us call this + resident mesh $\mathcal{M}_a$ for clarity. +- Next, the variable ~m2~ is defined as a copy of the variable ~m1~. It is + a copy of the variable, but its content is *the same*. The variable ~m2~ + is also referring to the mesh $\mathcal{M}_a$: there is no + duplication of the mesh in memory. +- Then, the variable ~m3~ is defined to refer to a *new* mesh (called + $\mathcal{M}_b$. It is /similar/ to $\mathcal{M}_a$, but it is *not* the + same one! When ~m3~ is defined two meshes $\mathcal{M}_a$ and + $\mathcal{M}_b$ (and two distinct connectivities) are resident in + memory. +- Finally, the last instruction (~m3 = m1;~) sets ~m3~ to also refer + $\mathcal{M}_a$. Since no other variable refers to $\mathcal{M}_b$, + this mesh is destroyed (memory is freed). At the end of the program, + all the variables ~m1~, ~m2~ and ~m3~ are referring to $\mathcal{M}_a$ + which is the only mesh that resides in memory. *** Compound types @@ -1812,7 +1787,7 @@ boundary conditions to a method. The ~pugs~ language supports classical statements to control the data flow. For simplicity, these statements syntax follow their ~C++~ counterpart. The only statement that is not implemented in ~pugs~ is the -~switch...case~. This may change but in the one hand, up now to it was +~switch...case~. This may change but in the one hand, up to now it was never necessary (we did not use chained ~if...else~ statements), and on the other hand, keeping the language as simple as possible remains the policy in ~pugs~ development. @@ -1868,15 +1843,6 @@ the conditional statements to use instruction blocks: cout << "sin(100)>0: " << sin100_positive << "\n"; #+END_SRC #+results: if-else-block-of-one -Obviously in this simple case, it would be better to write -#+BEGIN_SRC pugs :exports both :results output - import math; - let sin100_positive:B, sin100_positive = (sin(100) > 0); - // parenthesis are useless but ease reading - - cout << "sin(100)>0 ? " << sin100_positive << "\n"; -#+END_SRC -but this is not the purpose here. We give a final illustration #+NAME: if-block @@ -1966,20 +1932,6 @@ construction which executes /at least/ one time the enclosed ~statement~. The ~statement~ is either a single instruction or a block of instructions. The ~condition~ is an expression of boolean value (type ~B~). - -#+NAME: do-while-instr -#+BEGIN_SRC pugs :exports both :results output - let sum:N, sum = 0; - let i:N, i = 0; - do - sum += i++; - while (i<=10); - cout << "sum = " << sum << "\n"; -#+END_SRC -This code produces -#+results: do-while-instr - -However, to ease the reading, it is probably better to write #+NAME: do-while-block #+BEGIN_SRC pugs :exports both :results output let sum:N, sum = 0; @@ -1990,7 +1942,7 @@ However, to ease the reading, it is probably better to write } while (i<=10); cout << "sum = " << sum << "\n"; #+END_SRC -It gives also +It gives #+results: do-while-block *** ~while~ loops @@ -2012,7 +1964,7 @@ An example of the ~while~ loop is the following. #+BEGIN_SRC pugs :exports both :results output let sum:N, sum = 0; let i:N, i = 1; - while (sum<=10) { + while (i<=10) { sum += i; ++i; } @@ -2030,7 +1982,7 @@ statements. They follow their ~C++~ counterparts. - The ~continue~ keyword is used to skip the instructions that follow in the loop statement and continue the loop. -- The ~break~ keyword is leaves the current loop. +- The ~break~ keyword leaves the current loop. An example of use of the ~continue~ keyword is #+NAME: nested-continue @@ -2106,11 +2058,10 @@ functions. They act as operators. #+BEGIN_note Actually these functions are not strictly /pure functions/ in the -computer science sense. The reason for that is that they can -eventually have side effects. A good example for that, is that it is -possible to modify the random seed used by the code. In that case, the -modified value is not a variable of the language itself but the -internal random seed. +computer science sense. The reason is that they can eventually have +side effects. As an example, it is possible to modify the random seed +used by the code. In that case, the modified value is not a variable +of the language itself but the internal random seed. #+END_note *** Implicit type conversion for parameters and returned values @@ -2159,7 +2110,7 @@ returned type #+BEGIN_SRC pugs :exports both :results output let f: R -> R^1, x -> 2*x; - cout << "f(3.2) = " << f(2.3) << "\n"; + cout << "f(3.2) = " << f(3.2) << "\n"; #+END_SRC #+results: R-to-R1-function @@ -2218,18 +2169,19 @@ in function expressions. let plus: R -> R, x -> (x>0)*a; cout << "a = " << a << "\n"; - cout << "plus(2.2) = " << plus(2.2) << "\n"; + cout << "plus(2.2) = " << plus(2.2) << "\n"; cout << "plus(-3.2) = " << plus(-3.2) << "\n"; a = 2; cout << "a = " << a << "\n"; - cout << "plus(2.2) = " << plus(2.2) << "\n"; + cout << "plus(2.2) = " << plus(2.2) << "\n"; cout << "plus(-3.2) = " << plus(-3.2) << "\n"; #+END_SRC +Running the example, one gets +#+results: non-arg-variables-in-functions While the function itself is a constant object, one sees that since the value of ~a~ is changed, the value function is implicitly modified. /This is a dangerous feature and should be avoid!/ -#+results: non-arg-variables-in-functions Since functions themselves are variables one can use functions in function expressions.