 Paradoxe de Parrondo

Présentation

Soit $A$ un jeu de pile ou face avec une pièce biaisée (pile avec une probabilité de $p=\frac12-\varepsilon$, face avec une probabilité de $\frac12+\varepsilon$ où $\varepsilon>0$). On lance la pièce. Si on obtient pile, on gagne un jeton (ou un euro); sinon on perd un jeton (ou un euro).

Soit $B$ un jeu avec deux pièces biaisées. La pièce 1 donne pile avec une probabilité $p_1=\frac1{10}-\varepsilon$ et la pièce 2 donne pile avec une probabilité $p_2=\frac34-\varepsilon$. Si le joueur a un capital $K$ (de jetons ou d'euros) qui est un multiple de $m=3$, on lance la pièce 1, sinon on lance la pièce 2.
Comme dans le jeu $A$, si on obtient pile, on gagne un jeton (ou un euro); sinon on perd un jeton (ou un euro).

Soit $AB$ un jeu avec une pièce non biaisée. On lance la pièce. Si on obtient pile, on joue à $A$; sinon on joue à $B$.

On joue aléatoirement, 100 fois, au jeu $A$ ou au jeu $B$. C'est-à-dire qu'avec une pièce non biaisée, on décide - à chaque tour - si on joue à $A$ ou à $B$.

Questions

On prend $\varepsilon=\frac5{1000}$.

On démarre avec un capital $K=0$.

 Simuler 100 000 fois, l'évolution du capital $K$ d'un joueur qui joue $k$ fois au jeu $A$ avec $k\in[1,100]$. On pourra tracer l'évolution de la moyenne de $K$ en fonction de $k$ à la fin de l'exercice pour vérifier que $A$ est un jeu perdant (i.e. qui provoque la ruine du joueur s'il joue suffisamment longtemps).
On commencera par créer:

 une fonction $jeuA(p)$ qui prend en argument p la probabilité p et qui renvoie le gain du joueur (s'il gagne ou perd au lancer de pièce).

 Une fonction $playA(p)$ qui prend le même argument et qui simule une partie de 100 tours du jeuA et renvoie la liste du capital à chaque tour.

 Une fonction $simulation(p)$ prenant le même argument, qui simmule 100 000 fois une partie de 100 tours et renvoie sous forme de liste la moyenne (sur 100000 calcul) du capital du joueur à chaque tour.

```ocaml
open Random;;
Random.self_init;;

let k0=0;;

let jeuA p =
    if Random.float 1.<=p then 1 else (-1)

let playA p =
    let nbre_jeux = 100 in
    let k = k0 in
    let resultat = Array.make nbre_jeux 0 in
    let rec loop num k =
        if num<nbre_jeux then begin
            let k' = k+(jeuA p) in
            resultat.(num)<-k;
            loop (num+1) k';
        end else resultat in
    loop 0 k;;

let array_add a b =
    Array.init (Array.length a) (fun i->a.(i)+b.(i));;

let simulationA p =
    let rec loop num total_A =
        if num<100000
        then loop (num+1) (array_add total_A (playA p))
        else total_A in
    let total_A = loop 0 (Array.make 100 0) in
    Array.init 100 (fun i->float_of_int total_A.(i)/.(float_of_int 100000));;
```

- : unit -> unit = <fun>

val k0 : int = 0

val jeuA : float -> int = <fun>

val playA : float -> int array = <fun>

val array_add : int array -> int array -> int array = <fun>

val simulationA : float -> float array = <fun>

```ocaml
let pA1=1./.2.-.0.005 in
let res = (simulationA pA1).(99) in
assert ((float_of_int k0)+.(2.*.pA1-.1.-.0.01)*.100. < res && res < (float_of_int k0)+.(2.*.pA1-.1.+.0.01)*.100.)
```

- : unit = ()

 Quelle est l'espérance $E_A$ du jeu $A$ en utilisant les formule de probabilité traditionelle ? On pourra tracer $E_A$ en fonction de $k$ à la fin de l'exercice pour vérifier que ce calcul se superpose à la simulation précédente.

```ocaml
let calculA n p =
    (* esperance du jeu A au bout de n tours *)
    (float_of_int k0)+.(float_of_int n)*.(2.*.p-.1.)
```

val calculA : int -> float -> float = <fun>

```ocaml
let pA1=1./.2.-.0.005 in
let res1 = calculA 100 pA1 in
let res2 = calculA 1000 pA1 in
assert (res1=(float_of_int k0+.100.*.(2.*.pA1-.1.)) && res2= (float_of_int k0+.1000.*.(2.*.pA1-.1.)))
```

- : unit = ()

 Simuler 100 000 fois, l'évolution du capital $K$ d'un joueur qui joue $k$ fois au jeu $B$ avec $k\in[1,100]$. On pourra tracer l'évolution de la moyenne de $K$ en fonction de $k$ pour vérifier que $B$ est un jeu perdant.
On commencera par créer:

 une fonction $jeuB(K,p1,p2)$ qui prend en argument K le capital, p1 et p2 les probabailtés et qui renvoie le gain du joueur (s'il gagne ou perd au lancer de pièce).

 Une fonction $playB(p1,p2)$ qui simule une partie de 100 tours du jeuB et renvoie la liste du capital à chaque tour.

 Une fonction $simulationB(p)$ prenant le même argument, qui simmule 100 000 fois une partie de 100 tours et renvoie sous forme de liste la moyenne (sur 100000 calcul) du capital du joueur à chaque tour.

```ocaml
let jeuB k p1 p2 =
    (*
    k = kapital
    p1 = proba de gain si K est multiple de 3
    p2 = proba de gain si K n'est pas multiple de 3
    *)
    if k mod 3=0 then
        if Random.float 1.<=p1 then 1 else (-1)
    else
        if Random.float 1.<=p2 then 1 else (-1);;

let playB p1 p2 =
    let nbre_jeux = 100 in
    let k = k0 in
    let resultat = Array.make nbre_jeux 0 in
    let rec loop num k =
        if num<nbre_jeux then begin
            let k' = k + jeuB k p1 p2 in
            resultat.(num)<-k';
            loop (num+1) k';
        end else resultat in
    loop 0 k;;

let simulationB p1 p2 =
    let rec loop num total_B =
        if num<100000
        then loop (num+1) (array_add total_B (playB p1 p2))
        else total_B in
    let total_B = loop 0 (Array.make 100 0) in
    Array.init 100 (fun i->float_of_int total_B.(i)/.(float_of_int 100000));;
```

val jeuB : int -> float -> float -> int = <fun>

val playB : float -> float -> int array = <fun>

val simulationB : float -> float -> float array = <fun>

 Quelle est l'espérance $E_B$ du jeu $B$ ? (On calculera les probabilités par récurrence).Tracer $E_B$ en fonction de $k$ à la fin de l'exercice pour vérifier que ce calcul se superpose à la simulation précédente.

```ocaml
let list_pos liste element =
    let n = List.length liste in
    let rec loop pos liste =
        if pos<n then
            if List.hd liste = element
            then pos
            else loop (pos+1) (List.tl liste)
        else -1 in
    loop 0 liste;;
```

val list_pos : 'a list -> 'a -> int = <fun>

```ocaml
let pB1=1./.10.-.0.005;;
let pB2=3./.4.-.0.005;;

let calculB n p1 p2 =
    let liste_proba_param = ref [] in
    let liste_proba_val   = ref [] in

    let rec proba_B k n =
        (*proba d'avoir le capital k au n-ième tour*)
        let pos = list_pos !liste_proba_param (k,n) in
        if pos != -1 then List.nth !liste_proba_val pos
        else if n=0 && k=k0 then begin
            liste_proba_param:= (k0,0)::!liste_proba_param;
            liste_proba_val  := 1.::!liste_proba_val;
            1.
        end else if k-k0 = n then begin
            if (k-1) mod 3 =0 then begin
                let res = (proba_B (k-1) (n-1))*.p1 in
                liste_proba_param:= (k,n)::!liste_proba_param;
                liste_proba_val  := res::!liste_proba_val;
                res
            end else begin
                let res = (proba_B (k-1) (n-1))*.p2 in
                liste_proba_param:= (k,n)::!liste_proba_param;
                liste_proba_val  := res::!liste_proba_val;
                res end
        end else if k-k0 = (-n) then begin
            if (k+1) mod 3=0 then begin
                let res = (proba_B (k+1) (n-1))*.(1.-.p1) in
                liste_proba_param:= (k,n)::!liste_proba_param;
                liste_proba_val  := res::!liste_proba_val;
                res
            end else begin
                let res = (proba_B (k+1) (n-1))*.(1.-.p2) in
                liste_proba_param:= (k,n)::!liste_proba_param;
                liste_proba_val  := res::!liste_proba_val;
                res end
        end else begin
            let pi = (if (k-1) mod 3=0 then p1 else p2) in
            let qi = (if (k+1) mod 3=0 then (1.-.p1) else (1.-.p2)) in
            let res = proba_B(k-1) (n-1)*.pi+.proba_B(k+1) (n-1)*.qi in
            liste_proba_param:= (k,n)::!liste_proba_param;
            liste_proba_val  := res::!liste_proba_val;
            res end in

    let esperance_B n =
        let rec loop k e =
            if k<k0+n+1
            then loop (k+2) (e+.(float_of_int k)*.(proba_B k n))
            else e in
        loop (k0-n) 0. in

    esperance_B n;;
```

val pB1 : float = 0.095

val pB2 : float = 0.745

val calculB : int -> float -> float -> float = <fun>

```ocaml
let res1 = (simulationB pB1 pB2).(99) in
let res2 = calculB 100 pB1 pB2 in
print_float res1;print_newline();print_float res2;
assert (res2-.0.03 <res1 && res1<res2+.0.03)
```

    -1.40492
    -1.39232016825

- : unit = ()

 Simuler 100 000 fois, l'évolution du capital $K$ d'un joueur qui joue $k$ fois au jeu $AB$ avec $k\in[1,100]$. Tracer l'évolution de la moyenne de $K$ en fonction de $k$.

```ocaml
let playA_et_B p p1 p2 =
    let nbre_jeux = 100 in
    let k = k0 in
    let resultat = Array.make nbre_jeux 0 in
    let rec loop num k =
        if num<nbre_jeux then begin
            let k' = (if Random.float 1.<0.5
                      then k+(jeuA p)
                       else k+(jeuB k p1 p2)) in
            resultat.(num)<-k';
            loop (num+1) k'
        end else resultat in
    loop 0 k;;
```

val playA_et_B : float -> float -> float -> int array = <fun>

 Quelle est l'espérance $E_{AB}$ de ce jeu ? (On calculera les probabilités par récurrence). Tracer $E_{AB}$ en fonction de $k$. Vérifier que ce calcul se superpose à la simulation précédente.

```ocaml
let calculAB n p p1 p2 =
    let liste_proba_param = ref [] in
    let liste_proba_val   = ref [] in

    let rec proba_A k n =
        (*proba d'avoir le capital k en jouant au jeu A n-ième tour*)
        (proba_AB (k-1)(n-1))*.p+.(proba_AB (k+1)(n-1))*.(1.-.p)

    and proba_B k n =
        (*proba d'avoir le capital k en jouant au jeu B n-ième tour*)
        let pi = (if (k-1) mod 3=0 then p1 else p2) in
        let qi = (if (k+1) mod 3=0 then (1.-.p1) else (1.-.p2)) in
        (proba_AB (k-1) (n-1))*.pi+.(proba_AB (k+1) (n-1))*.qi

    and proba_AB k n =
        let pos = list_pos !liste_proba_param (k,n) in
        if pos != -1 then List.nth !liste_proba_val pos
        else if n=0 && k=k0 then begin
                liste_proba_param:=(k0,0)::!liste_proba_param;
                liste_proba_val  :=1.::!liste_proba_val;
                1. end
        else if abs(k-k0)>n then begin
                liste_proba_param:=(k,n)::!liste_proba_param;
                liste_proba_val  :=0.::!liste_proba_val;
                0. end
        else begin
            let res = 0.5*.(proba_A k n)+.0.5*.(proba_B k n) in
            liste_proba_param:=(k,n)::!liste_proba_param;
            liste_proba_val  :=res::!liste_proba_val;
            res end in

    let esperance_AB n =
        let rec loop k e =
            if k<k0+n+1
            then loop (k+1) (e+.(float_of_int k)*.(proba_AB k n))
            else e in
        loop (k0-n) 0. in

    esperance_AB n;;
```

val calculAB : int -> float -> float -> float -> float = <fun>

```ocaml
let range debut fin step =
   let rec range i acc =
     if i>=fin then List.rev acc
     else range (i+step) (i::acc) in
   range debut [];;
```

val range : int -> int -> int -> int list = <fun>

```ocaml
let array_min array = Array.fold_right min array array.(0);;
let array_max array = Array.fold_right max array array.(0);;
```

val array_min : 'a array -> 'a = <fun>

val array_max : 'a array -> 'a = <fun>

```ocaml
#use "topfind";;
#require "plplot";;
open Plplot;;
module P = Plot;;
let couleurs_list = [[ 0;255;255;255]; (*`white*)
                     [ 1;  0;  0;  0]; (*`black*)
                     [ 2;  0;  0;255]; (*`blue*)
                     [ 3;255;  0;  0]; (*`red*)
                     [ 4;165; 42; 42]; (*`brown*)
                     [ 5;  0;  0;  0]; [ 6;  0;  0;  0]; [ 7;  0;  0;  0]; [ 8;  0;  0;  0]; [ 9;  0;  0;  0];
                     [10;200;200;200]; (*`gray*)
                     [11;  0;255;255]; (*`light_blue*)
                     [12;  0;255;  0]; (*`green*)
                     [13;255;255;  0]; (*`yellow*)
                     [14;255;  0;255]; (*`pink*)
                     [15;160;  0;213]; (*`purple*) ]
let rec loop couleurs_list = match couleurs_list with
    | [n;r;g;b]::tl -> plscol0 n r g b; loop tl
    | _ -> ();;
let couleurs = (fun () -> plscolbg 255 255 255; loop couleurs_list)
let initialisation filename xmin xmax ymin ymax =
        P.init (xmin, ymin) (xmax, ymax) `greedy (`svg `core) ~filename:(filename^".svg") ~pre:couleurs
let xlabel texte = P.text_outside `black (`bottom 0.5) 3. texte
let ylabel texte = P.text_outside `black (`left 0.5) 5. texte
let label texte_x texte_y titre = P.label texte_x texte_y titre
```

    - : unit = ()
    Findlib has been successfully loaded. Additional directives:
      #require "package";;      to load a package
      #list;;                   to list the available packages
      #camlp4o;;                to load camlp4 (standard syntax)
      #camlp4r;;                to load camlp4 (revised syntax)
      #predicates "p,q,...";;   to set these predicates
      Topfind.reset();;         to force that packages will be reloaded
      #thread;;                 to enable threads

    - : unit = ()

    /usr/lib/ocaml/plplot: added to search path
    /usr/lib/ocaml/plplot/plplot.cma: loaded

module P = Plplot.Plot

val couleurs_list : int list list =
  [[0; 255; 255; 255]; [1; 0; 0; 0]; [2; 0; 0; 255]; [3; 255; 0; 0];
   [4; 165; 42; 42]; [5; 0; 0; 0]; [6; 0; 0; 0]; [7; 0; 0; 0]; [8; 0; 0; 0];
   [9; 0; 0; 0]; [10; 200; 200; 200]; [11; 0; 255; 255]; [12; 0; 255; 0];
   [13; 255; 255; 0]; [14; 255; 0; 255]; [15; 160; 0; 213]]

val loop : int list list -> unit = <fun>

val couleurs : unit -> unit = <fun>

val initialisation : string -> float -> float -> float -> float -> P.stream_t =
  <fun>

val xlabel : string -> P.plot_t = <fun>

val ylabel : string -> P.plot_t = <fun>

val label : string -> string -> string -> P.plot_t = <fun>

```ocaml
let epsilon=5./.1000.;;
let p=1./.2.-.epsilon;;
let p1=1./.10.-.epsilon;;
let p2=3./.4.-.epsilon;;
let nbre_jeux=100;;
let nbre_essais=100*1000;;
let rec loop num total_A total_B total_A_et_B =
    if num<nbre_essais
    then loop (num+1)
              (array_add total_A (playA p))
              (array_add total_B (playB p1 p2))
              (array_add total_A_et_B (playA_et_B p p1 p2))
    else begin
        let convert array = Array.init nbre_jeux
        (fun i->float_of_int array.(i)/.(float_of_int nbre_essais)) in
        (convert total_A),(convert total_B),(convert total_A_et_B);
    end;;
let total_A, total_B, total_A_et_B = loop 0
                                        (Array.make nbre_jeux 0)
                                        (Array.make nbre_jeux 0)
                                        (Array.make nbre_jeux 0);;

let liste_k = range 1 (nbre_jeux+1) 1 in
let xs = Array.of_list (List.map float_of_int liste_k) in
let total_A_th = Array.of_list (List.map (fun k -> calculA k p) liste_k) in
let total_B_th = Array.of_list (List.map (fun k -> calculB k p1 p2) liste_k) in
let total_A_et_B_th = Array.of_list (List.map (fun k -> calculAB k p p1 p2) liste_k) in

let p = initialisation "graph" (array_min xs) (array_max xs) (-.2.) 2.
(*(array_min total_A) (array_max total_A_et_B)*) in
P.plot ~stream:p [P.points ~symbol:"+" `blue xs total_A_th;
                  P.points ~symbol:"+" `green xs total_B_th;
                  P.points ~symbol:"+" `red xs total_A_et_B_th;
                  P.lines `blue xs total_A;
                  P.lines `green xs total_B;
                  P.lines `red xs total_A_et_B;
                  P.label "Tour" "Esperance" "Paradoxe de Parrondo";
                  P.legend ~pos:(P.viewport_pos 0.45 0.) ~text_offset:0. ~text_justification:0.
                          [[P.symbol_legend "récurrence jeu A" `blue "+"];
                           [P.symbol_legend "récurrence jeu B" `green "+"];
                           [P.symbol_legend "récurrence jeu A et B" `red "+"];
                           [P.line_legend "Monte Carlo jeu A" `blue];
                           [P.line_legend "Monte Carlo jeu B" `green];
                           [P.line_legend "Monte Carlo jeu A et B" `red]]];
P.finish ~stream:p ();;

```

val epsilon : float = 0.005

val p : float = 0.495

val p1 : float = 0.095

val p2 : float = 0.745

val nbre_jeux : int = 100

val nbre_essais : int = 100000

val loop :
  int ->
  int array ->
  int array -> int array -> float array * float array * float array = <fun>

val total_A : float array =
  [|0.; -0.01128; -0.01634; -0.02648; -0.03196; -0.04514; -0.05542; -0.06038;
    -0.06922; -0.08074; -0.0967; -0.10258; -0.11188; -0.12342; -0.13468;
    -0.14356; -0.15222; -0.1593; -0.16916; -0.17562; -0.18534; -0.18926;
    -0.19962; -0.20852; -0.22386; -0.23016; -0.24702; -0.2618; -0.27794;
    -0.28866; -0.29892; -0.30746; -0.31374; -0.32276; -0.33436; -0.34536;
    -0.35436; -0.37; -0.37498; -0.3864; -0.39136; -0.40726; -0.4135;
    -0.42642; -0.43678; -0.4507; -0.45066; -0.46116; -0.47224; -0.48208;
    -0.49572; -0.50804; -0.52302; -0.53362; -0.54596; -0.55588; -0.56814;
    -0.58016; -0.59008; -0.602; -0.60734; -0.61782; -0.62994; -0.6425;
    -0.6516; -0.66322; -0.67318; -0.68358; -0.69628; -0.70352; -0.70792;
    -0.7146; -0.72738; -0.733; -0.74558; -0.7552; -0.77154; -0.7822;
    -0.79208; -0.80552; -0.81416; -0.82858; -0.84004; -0.84838; -0.86308;
    -0.87384; -0.88274; -0.88626; -0.89692; -0.90494; -0.9131; -0.92428;
    -0.93918; -0.94166; -0.94854; -0.95688; -0.96332; -0.97266; -0.98482;
    -0.99124|]
val total_B : float array =
  [|-0.80792; -0.3135; -0.73172; -0.38172; -0.69896; -0.44116; -0.68286;
    -0.4877; -0.6693; -0.52272; -0.66806; -0.55646; -0.66156; -0.58518;
    -0.67058; -0.61296; -0.68148; -0.63418; -0.69144; -0.65976; -0.70306;
    -0.68356; -0.71998; -0.70162; -0.73376; -0.72076; -0.7464; -0.73654;
    -0.75754; -0.75464; -0.77722; -0.77902; -0.79594; -0.79576; -0.81146;
    -0.81254; -0.824; -0.83032; -0.84288; -0.84574; -0.85852; -0.86876;
    -0.87982; -0.8889; -0.90154; -0.91176; -0.92144; -0.927; -0.93504;
    -0.94146; -0.94748; -0.9571; -0.9656; -0.97468; -0.98304; -0.99034;
    -0.99964; -1.00944; -1.0209; -1.03164; -1.04; -1.0483; -1.05904;
    -1.06574; -1.07402; -1.09078; -1.0984; -1.103; -1.1125; -1.12178;
    -1.1336; -1.14254; -1.15444; -1.16398; -1.1728; -1.1818; -1.18652;
    -1.1971; -1.20908; -1.2226; -1.2312; -1.24116; -1.2531; -1.25906;
    -1.2709; -1.27672; -1.28468; -1.29606; -1.30496; -1.31092; -1.31574;
    -1.32714; -1.33952; -1.3459; -1.35498; -1.36264; -1.36826; -1.38148;
    -1.3891; -1.39794|]
val total_A_et_B : float array =
  [|-0.41398; -0.1735; -0.2832; -0.18238; -0.2259; -0.16926; -0.17712;
    -0.1463; -0.13554; -0.11178; -0.1015; -0.08402; -0.07738; -0.06034;
    -0.04838; -0.03648; -0.02294; -0.01314; -0.00582; 0.01118; 0.02852;
    0.04706; 0.06536; 0.08194; 0.09436; 0.11024; 0.13116; 0.14564; 0.16172;
    0.17816; 0.19568; 0.2076; 0.2249; 0.23938; 0.26024; 0.27824; 0.29408;
    0.31076; 0.321; 0.33364; 0.3406; 0.35764; 0.37514; 0.39176; 0.40502;
    0.42406; 0.43732; 0.4561; 0.471; 0.4865; 0.50606; 0.51748; 0.5382;
    0.54878; 0.5643; 0.5747; 0.58996; 0.61062; 0.62698; 0.6403; 0.65516;
    0.6684; 0.68022; 0.6958; 0.7114; 0.72552; 0.74326; 0.76028; 0.77386;
    0.79114; 0.80312; 0.81902; 0.83356; 0.85224; 0.8715; 0.88152; 0.89872;
    0.91388; 0.92874; 0.94552; 0.95868; 0.97228; 0.98788; 1.0028; 1.02162;
    1.03846; 1.05352; 1.0673; 1.07738; 1.09614; 1.11458; 1.13412; 1.15132;
    1.1637; 1.17514; 1.1906; 1.20672; 1.22148; 1.24044; 1.2534|]

- : unit = ()

  $A$ et $B$ sont des jeux perdants. Le jeu $AB$ est-il également  perdant ?

 Explication

La probabilité de gagner au jeu $B$ s'écrit: $P_B=\alpha.p_1+(1-\alpha).p_2$ avec $\alpha$ la probabilité que le capital soit un multiple de $m=3$ (i.e. la probabilité de lancer la pièce 1). On voit sur la simulation que $P_B<\frac12$ puisque $B$ est un jeu perdant.

D'où $\alpha.(\frac1{10}-\frac34)+\frac34-\varepsilon<\frac12$
$\Rightarrow$ $\alpha>(\frac14-\varepsilon).\frac{20}{13}=\frac{245}{650}=\frac{49}{130}\simeq0.37>\frac13$.

Dans le jeu $B$, la probabilité de tomber sur un multiple de 3 est supérieure à $\frac13$.

La probabilité de gagner au jeu $AB$ s'écrit: $P_{AB}=\frac12.p+\alpha'.p_1+(\frac12-\alpha').p_2$ avec $\alpha'$ la probabilité de lancer la pièce 1. (Somme des probabilités $\frac12+\alpha'+(\frac12-\alpha')=1$). On voit sur la simulation que $P_{AB}>\frac12$ puisque $AB$ est un jeu gagnant.

D'où $\alpha'.(\frac1{10}-\frac34)+\frac58-\varepsilon>\frac12$
$\Rightarrow$ $\alpha'<(\frac18-\varepsilon).\frac{20}{13}=\frac{24}{130}\simeq 0,18<\frac13$.

Dans le jeu $AB$, la probabilité de jouer la pièce 1 est inférieure à $\frac13$.

Chaine de Markov

Un processus markovien est un processus dans lequel les probabilités pour aller vers les configurations au tour $k+1$ ne dépendent que des configurations au tour $k$ (mémoire limité à un tour).

Jeu $B$

On considère d'abord le jeu $B$ avec trois états:

⓪ correspondant à un capital $K\equiv0\,[3]$

① capital $K\equiv 1\,[3]$

② capital $K\equiv 2\,[3]$

On a le graphe suivant (avec $q_i=1-p_i$):

Au tour n${}^\circ k$, les probabilités de présence du système dans les différents états sont représentées par un vecteur ligne $\vec V_k$.
La matrice de transition $[T]$ vers l'état suivant s'écrit:

$[T]=\begin{bmatrix}
0 & p_1 & q_1 \\
q_2 & 0 & p_2\\
p_2 & q_2 & 0
\end{bmatrix}$

Au tour n${}^\circ k+1$, les probabilités de présence dans les différents états s'obtiennent par: $\vec V_{k+1}=\vec V_k.[T]$.
Par exemple, si on part de l'état 0 représenté par [1,0,0], l'état suivant sera: $[1,0,0].[T]=[0,p_1,q_1]$.

Dans le cas général, $[T]$ est défini par $T_{ij}=Pr(K_{k+1}=j | K_k=i)$.

La matrice transposée s'écrit: ${}^t[T]=\begin{bmatrix}
0 & q_2 & p_2 \\
p_1 & 0 & q_2\\
q_1 & p_2 & 0
\end{bmatrix}$.

Pour obtenir le temps moyen d'occupation de chaque état, il faut trouver les états stationnaires en cherchant le vecteur propre associé à la valeur propre 1 (https://fr.wikipedia.org/wiki/Probabilit%C3%A9_stationnaire_d%27une_cha%C3%AEne_de_Markov).

Dans ce vecteur propre $\vec v=\begin{bmatrix}v_0\\ v_1\\ v_2\end{bmatrix}$, $v_0$ représente la limite asymptotique du temps moyen d'occupation de l'état 0, $v_1$ le temps moyen de l'occupation de l'état 1 et $v_2$ le temps moyen d'occupation de l'état 2.

On obtient $\vec v=\begin{bmatrix}
(1-p_2+p_2^2)/S\\
(1-p_2+p_1.p_2)/S\\
(1-p_1+p_1.p_2)/S
\end{bmatrix}$ où $S$ est tel que la somme des composantes de $\vec v$ soit égale à 1.

On obtient $\alpha$ d'après $v_0$ la première composante de $\vec v$:

$\alpha=\frac{1-p_2+p_2^2}{3-p_1-2.p_2+2.p_1.p_2+p_2^2}$

.

On trouve: $\alpha=0.38361175899506295$ d'où

$P_B= \alpha.p_1+(1-\alpha).p_2=0.49565235665320906<0.5$

Le jeu $B$ est bien perdant[1].

[1]
L'article https://fr.wikipedia.org/wiki/Paradoxe_de_Parrondo est faux: si $p_1=\varepsilon$ et $p_2=\frac34-2.\varepsilon$, alors $\alpha=\frac{-\varepsilon^2 + 0.5.\varepsilon - 0.8125}{\varepsilon^2 - \varepsilon - 2.0625}=0.391794338504698\neq\frac13$ pour $\varepsilon=\frac5{1000}$.

On peut tracer l'ensemble des couples $(p_1,p_2)$ donnant un jeu $B$ perdant.
Le point correspond au couple $(p_1,p_2)$ choisi dans cet exemple.

Jeu $AB$

On considère maintenant le jeu $AB$ avec six états:

⓪ $K\equiv0\,[3]$ et jeu $A$,

① $K\equiv 1\,[3]$ et jeu $A$;

② $K\equiv 2\,[3]$ et jeu $A$;

③ $K\equiv0\,[3]$ et jeu $B$,

④ $K\equiv 1\,[3]$ et jeu $B$;

⑤ $K\equiv 2\,[3]$ et jeu $B$.

On a le graphe suivant:

La matrice de transition $[T]$ vers l'état suivant s'écrit: $[T]=\frac12.\begin{bmatrix}
0 & p & q & 0 & p & q\\
q & 0 & p & q & 0 & p \\
p & q & 0 & p & q & 0 \\
0 & p_1 & q_1 & 0 & p_1 & q_1 \\
q_2 & 0 & p_2 & q_2 & 0 & p_2 \\
p_2 & q_2 & 0 & p_2 & q_2 & 0
\end{bmatrix}$.

La matrice transposée s'écrit: ${}^t[T]=\frac12.\begin{bmatrix}
0 & q & p & 0 & q_2 & p_2 \\
p & 0 & q & p_1 & 0 & q_2\\
q & p & 0 & q_1 & p_2 & 0\\
0 & q & p & 0 & q_2 & p_2 \\
p & 0 & q & p_1 & 0 & q_2\\
q & p& 0 & q_1 & p_2 & 0\\
\end{bmatrix}$.

Le vecteur propre associé à la valeur propre 1 est $\vec v=\begin{bmatrix}
v_0 \\ v_1 \\ v_2 \\ v_3 \\ v_4 \\ v_5 \end{bmatrix}$.

On montre que $v_0=v_3$, $v_1=v_4$ et $v_2=v_5$.

On a: $v_0=\frac{4-(q+q_2).(p+p_2)}{S}$, $v_1=\frac{2.(p+p_1)+(q+q_1).(q+q_2)}{S}$
et $v_2=\frac{2.(q+q_1)+(p+p_1).(p+p_2)}{S}$ où $S$ est tel que la somme des composantes de $\vec v$ est égale à 1. On a: $S=6.p^2 + 4.p.p_1 + 8.p.p_2 - 12.p + 4.p_1.p_2 - 4.p_1 + 2.p_2^2 - 8.p_2 + 24$

La probabilité $\alpha'$ de lancer la pièce ayant la probabilité $p_1$ correspond à

 $\alpha'=v_3=v_0=\frac{p^2 + 2.p.p_2 - 2.p + p_2^2 - 2.p_2 + 4}{2.(3.p^2 + 2.p.p_1 + 4.p.p_2 - 6.p + 2.p_1.p_2 - 2.p_1 + p_2^2 - 4.p_2 + 12)}$.

On obtient $\alpha'=0.17253521$ d'où

 $P_{AB}=\frac12.p+\alpha'.p_1+(\frac12-\alpha').p_2=0.5078521>0.5$.

Le jeu $AB$ est bien gagnant !

Si on impose $p=\frac12-\frac5{1000}$, on peut tracer l'ensemble des couples $(p_1,p_2)$ donnant un jeu $AB$ gagnant.
Le point correspond au couple $(p_1,p_2)$ choisi dans cet exemple.

En superposant les deux graphes, on voit que la zone donnant $B$ perdant et $AB$ gagnant est très restreinte (pour $m=3$).

Généralisation au cas $m=4$

Pour le jeu $B$.

La matrice de transition $[T]$ vers l'état suivant s'écrit: $[T]=\begin{bmatrix}
0 & p_1 & 0  & q_1 \\
q_2 & 0 & p_2 & 0\\
0 & q_2 & 0 & p_2\\
p_2 & 0 & q_2 & 0
\end{bmatrix}$.

De la même façon: on transpose, on cherche le vecteur propre associé à la valeur propre 1, on norme le vecteur, on obtient $\alpha=\frac{2.p_2^2 - 2.p_2 + 1}
{2.(2.p_1.p_2 - p_1 + 2.p_2^2 - 3.p_2 + 2)}$

Le jeu $B$ est perdant si et seulement si: $P_B=\alpha.p_1+(1-\alpha).p_2<\frac12$.

Graphiquement, on peut tracer l'ensemble des couples $(p_1,p_2)$ donnant un jeu $B$ perdant.

Pour le jeu $AB$.

La matrice de transition $[T]$ vers l'état suivant s'écrit: $[T]=\frac12.\begin{bmatrix}
0 & p & 0  & q & 0 & p & 0  & q\\
q & 0 & p & 0 & q & 0 & p & 0\\
0 & q & 0 & p & 0 & q & 0 & p\\
p & 0 & q & 0 & p & 0 & q & 0 \\
0 & p_1 & 0  & q_1 & 0 & p_1 & 0  & q_1\\
q_2 & 0 & p_2 & 0 & q_2 & 0 & p_2 & 0\\
0 & q_2 & 0 & p_2 & 0 & q_2 & 0 & p_2\\
p_2 & 0 & q_2 & 0 & p_2 & 0 & q_2 & 0
\end{bmatrix}$.

De la même façon, on obtient:
$\alpha'=\frac{p^2 + 2.p.p_2 - 2.p + p_ 2^2 - 2.p_2 + 2}{4.(2.p^2 + p.p_1 + 3.p.p_2 - 4.p + p_1.p_2 - p_1 + p_2^2 - 3.p_2 + 4)}$

Le jeu $AB$ est gagnant ssi: $P_{AB}=\frac12.p+\alpha'.p_1+(\frac12-\alpha').p_2>\frac12$.

Si on impose $p=\frac12-\frac5{1000}$, on peut tracer l'ensemble des couples $(p_1,p_2)$ donnant un jeu $AB$ gagnant.

En superposant les deux graphes, on voit que la zone donnant $B$ perdant et $AB$ gagnant est  similaire au cas $m=3$.

On peut vérifier avec $m=4$, $p=\frac12-\frac5{1000}$, $p_1=0.025$ et $p_2=0.75$ (voir point sur le graphique) que l'on obtient un jeu $AB$ encore plus favorable que dans l'exemple précédent ($m=3$, $p=\frac12-\frac5{1000}$, $p_1=\frac1{10}-\frac5{1000}$ et $p_2=\frac34-\frac5{1000}$).

On peut continuer ainsi pour $m=5$, $m=6$, ...

Les calculs deviennent rapidement fastidieux. On peut résoudre le problème avec <tt> sympy</tt>.
Ci-dessous le cas $m=6$ pour le jeu $AB$.

from sympy import *
p,p1,p2=symbols("p,p1,p2")
q,q1,q2=symbols("q,q1,q2")
alpha=symbols("alpha")
q=1-p
q1=1-p1
q2=1-p2

M=Matrix([
[      -1, (q+q2)/2,        0,        0,        0],
[(p+p2)/2,       -1, (q+q2)/2,        0,        0],
[       0, (p+p2)/2,       -1, (q+q2)/2,        0],
[       0,        0, (p+p2)/2,       -1, (q+q2)/2],
[       0,        0,        0, (p+p2)/2,       -1]])
V=Matrix([
[-(p+p1)/2*alpha],
[0],
[0],
[0],
[-(q+q1)/2*alpha]])

Probas_etats_AB=M.inv()*V
Probas_etats_AB.simplify()
valeur_alpha_prime=solve(2*alpha+2*sum(Probas_etats_AB)-1,alpha)[0]

Pour le jeu $B$, il suffit de remplacer <t>p</t> par <t>p2</t> et <t>q</t> par <t>q2</t> dans la matrice <t>M</t> et <t>p</t> par <t>p1</t> et <t>q</t> par <t>q1</t> dans le vecteur <t>V</t>; la condition pour normer s'écrit:
<t> valeur\_alpha=solve(alpha+sum(Probas\_etats\_B)-1,alpha)[0]</t>.

\vskip\baselineskip
On obtient les valeurs de $\alpha$ et $\alpha'$ suivantes:

$m=5$
$\alpha=\frac{p_2^4 - 2.p_2^3 + 4.p_2^2 - 3.p_2 + 1}
{4.p_1.p_2^3 - 6.p_1.p_2^2 + 8.p_1.p_2 - 3.p_1 + p_2^4 - 4.p_2^3 + 12.p_2^2 - 12.p_2 + 5}$

$\alpha'=\frac{p^4 + 4.p^3.p_2 - 4.p^3 + 6.p^2.p_2^2 - 12.p^2.p_2 + 16.p^2 + 4.p.p_2^3 - 12.p.p_2^2 + 32.p.p_2 - 24.p + p_2^4 - 4.p_2^3 + 16.p_2^2 - 24.p_2 + 16}{2.(5.p^4 + 4.p^3.p_1 + 16.p^3.p_2 - 20.p^3 + 12.p^2.p_1.p_2 - 12.p^2.p_1 + 18.p^2.p_2^2 - 48.p^2.p_2 + 80.p^2 + 12.p.p_1.p_2^2 - 24.p.p_1.p_2 + 32.p.p_1 + 8.p.p_2^3 - 36.p.p_2^2 + 128.p.p_2 - 120.p + 4.p_1.p_2^3 - 12.p_1.p_2^2 + 32.p_1.p_2 - 24.p_1 + p_2^4 - 8.p_2^3 + 48.p_2^2 - 96.p_2 + 80)}$

$m=6$

$\alpha=\frac{3.p_2^4 - 6.p_2^3 + 7.p_2^2 - 4.p_2 + 1}{2.(6.p_1.p_2^3 - 9.p_1.p_2^2 + 7.p_1.p_2 - 2.p_1 + 3.p_2^4 - 9.p_2^3 + 14.p_2^2 - 10.p_2 + 3)}$

$\alpha'=\frac{ 3.p^4 + 12.p^3.p2 - 12.p^3 + 18.p^2.p2^2 - 36.p^2.p2 + 28.p^2 + 12.p.p2^3 - 36.p.p2^2 + 56.p.p2 - 32.p + 3.p2^4 - 12.p2^3 + 28.p2^2 - 32.p2 + 16}{4*(9.p^4 + 6.p^3.p1 + 30.p^3.p2 - 36.p^3 + 18.p^2.p1.p2 - 18.p^2.p1 + 36.p^2.p2^2 - 90.p^2.p2 + 84.p^2 + 18.p.p1.p2^2 - 36.p.p1.p2 + 28.p.p1 + 18.p.p2^3 - 72.p.p2^2 + 140.p.p2 - 96.p + 6.p1.p2^3 - 18.p1.p2^2 + 28.p1.p2 - 16.p1 + 3.p2^4 - 18.p2^3 + 56.p2^2 - 80.p2 + 48)}$

Les couples $(p_1,p_2)$ permettant d'observer le paradoxe de Parrondo (pour $p=\frac12-\frac5{1000}$) sont représentés ci-dessous (entre les deux courbes).

Conclusion

Dans la version originale du paradoxe de Parrondo, les probabilités dépendant du capital du joueur.
On n'a analysé ici seulement le cas où l'on joue aléatoirement aux jeux $A$ et $B$, mais
il existe des variantes du paradoxe où l'on joue aux jeux $A$ et $B$ selon une séquence déterminée (ex: $AABBAABB\dots$).

Il existe également des variantes où les probabilités dépendent des gains/pertes antérieurs.
Par exemple, le jeu $A$ est inchangé (gain avec une probabilité $p=\frac12-\varepsilon$) et le jeu $B$ nécessite maintenant trois pièces ayant respectivement des probabilités de gains $p_1$, $p_2$, $p_3$ (ex: $p_1=0.9-\varepsilon$, $p_2=0.25-\varepsilon$ et $p_3=0.7-\varepsilon$). Au tour n$^\circ k$, on joue l'une des pièces suivant les résultats des tours $k-1$ et $k-2$:

résultat du tour $k-2$
résultat du tour $k-1$
pièce à jouer au tour $k$

perdu
perdu
1

perdu
gagné
2

gagné
perdu
2

gagné
gagné
3

Les applications sont nombreuses: à la fois théorique (il y a une analogie avec le fameux cours de thermodynamique de Feynman sur le mouvement brownien avec une roue à cliquets (https://en.wikipedia.org/wiki/Brownian_ratchet) et pratique (système de spins, génétique humaine).

```ocaml

```


# System Properties

*This Jupyter notebook is part of a [collection of notebooks](../index.ipynb) in the bachelors module Signals and Systems, Communications Engineering, Universität Rostock. Please direct questions and suggestions to [Sascha.Spors@uni-rostock.de](mailto:Sascha.Spors@uni-rostock.de).*

## Idealized Systems

Idealized systems are systems with idealized properties that typically render their practical implementation infeasible. They play an important role in various fields of signal processing as they allow a convenient formulation of major concepts and principles. In the following, the ideal low-pass is introduced as prototype for an idealized frequency selective system. Other frequency selective systems can be deduced directly from this prototype.

### Ideal Low-Pass

The transfer function $H(j \omega)$ of a real-valued [ideal low-pass](https://en.wikipedia.org/wiki/Sinc_filter) reads

\begin{equation}
H(j \omega) = \text{rect} \left( \frac{\omega}{2 \omega_\text{c}} \right)
\end{equation}

where $\omega_\text{c} > 0$ denotes its cut-off frequency. The ideal low-pass removes all frequency components above the cut-off frequency $\omega_\text{c}$, without affecting lower frequencies. The impulse response $h(t) = \mathcal{F}^{-1} \{ H(j \omega) \}$ is computed by applying the [duality principle](../fourier_transform/properties.ipynb#Duality) to the [Fourier transform of the rectangular signal](../fourier_transform/definition.ipynb#Transformation-of-the-Rectangular-Signal)

\begin{equation}
h(t) = \frac{\omega_\text{c}}{\pi} \cdot \text{sinc} ( \omega_\text{c} t )
\end{equation}

Since the impulse response is an acausal signal, the ideal low-pass is an [acausal system](causality_stability.ipynb#Condition-for-the-Impulse-Response). The sinc-function is furthermore not absolutely integrable. Hence the ideal-low pass is not a [stable system](causality_stability.ipynb#Condition-for-the-Impulse-Response) in the sense of the bounded-input bounded-output (BIBO) criterion. In conclusion, the ideal low-pass is not realizable. It can only be approximated in practical systems. It plays nevertheless an important role in the theory of sampling and interpolation.

#### Realizable low-pass

Various techniques have been developed in order to approximate the ideal low-pass by a realizable system. One is the *windowed sinc filter*. In order to make the ideal-low pass filter causal and stable, its impulse response is windowed to a finite-length $T$ followed by a temporal shift of $\frac{T}{2}$. Using the [rectanglar signal](../continuous_signals/standard_signals.ipynb#Rectangular-Signal) to truncate (window) the impulse response, the impulse response of the realizable low-pass is given as

\begin{equation}
h(t) = \frac{\omega_\text{c}}{\pi} \cdot \text{sinc} \left( \omega_\text{c} \left(t - \frac{T}{2} \right) \right) \cdot \text{rect}\left( \frac{1}{T} \left( t - \frac{T}{2} \right) \right)
\end{equation}

Fourier transformation yields its transfer function

\begin{equation}
H(j \omega) = \frac{1}{2 \pi} e^{-j \omega \frac{T}{2}} \cdot \text{rect}\left( \frac{\omega}{2 \omega_c} \right) * T \cdot \text{sinc} \left( \frac{T}{2} \omega \right)
\end{equation}

The impulse response is plotted for $w_\text{c}=10$ and $T=5$

```python
import sympy as sym
%matplotlib inline
sym.init_printing()

t, w = sym.symbols('t omega', real=True)
wc = 10
T = 5

h = wc/sym.pi * sym.sinc(wc*(t-T/2))
sym.plot(h, (t, 0, T), xlabel='$t$', ylabel='$h(t)$')
```

    <sympy.plotting.plot.Plot at 0x10e55af60>

The transfer function $H(j \omega)$ of the realizable low-pass is given above in terms of a convolution integral over the rectangular and sinc signal. Applying the definition of the convolution and exploiting the properties of the rectangular signal yields

\begin{equation}
H(j \omega) = \frac{T}{2 \pi} e^{-j \omega \frac{T}{2}} \int_{-\omega_\text{c}}^{\omega_\text{c}} \text{sinc} \left( \frac{T}{2} (\nu - \omega) \right) d \nu
\end{equation}

No closed-form solution of this integral is known. In order to gain insight into the properties of the realizable low-pass, the transfer function is approximated by numerical integration for equally spaced angular frequencies $\omega$. Only positive angular frequencies are evaluated in order to lower the computational complexity. Note the symmetry relations of a real-valued system apply.

```python
from numpy import linspace, array
import matplotlib.pyplot as plt

nu = sym.symbols('nu', real=True)
w = linspace(0, 1.5*wc, 100)

H = [(T/(2*sym.pi)).evalf(2) * sym.exp(-sym.I*wi*T/2).evalf(2) *
     sym.Integral(sym.sinc(T/2*(nu-wi)), (nu, -wc, wc)).evalf(2) for wi in w]

plt.plot(w, abs(array(H)))
plt.xlabel('$\omega$')
plt.ylabel('$|H(j \omega)|$')
plt.grid()
```

**Exercise**

* Discuss the properties of the magnitude response $|H(j \omega)|$ of the realizable low-pass in dependence of its length $T$.

### Ideal Band-Pass

The transfer function $H(j \omega)$ of a real-valued ideal band-pass reads

\begin{equation}
H(j \omega) =
\begin{cases}
1 & \text{for }  \omega_\text{c} - \frac{\Delta \omega}{2} < |\omega| < \omega_\text{c} + \frac{\Delta \omega}{2} \\
0 & \text{otherwise}
\end{cases}
\end{equation}

The ideal band-pass does not affect the frequency components of a signal around a given center frequency $\omega_\text{c}$ where the total width of this transition band is $\Delta \omega$. Components outside the transition band are removed. The transfer function can be rewritten as

\begin{equation}
H(j \omega) =
\text{rect} \left( \frac{\omega - \omega_\text{c}}{\Delta \omega} \right) + \text{rect} \left( \frac{\omega + \omega_\text{c}}{\Delta \omega} \right)
= \text{rect} \left( \frac{\omega}{\Delta \omega} \right) * \left( \delta(\omega - \omega_\text{c}) + \delta(\omega + \omega_\text{c}) \right)
\end{equation}

Its impulse response is computed by inverse Fourier transformation

\begin{equation}
h(t) = \pi \Delta \omega \cdot \text{sinc} ( \frac{\Delta \omega}{2} t ) \cdot \cos(\omega_\text{c} t)
\end{equation}

The ideal band-pass can be interpreted as a modulated low-pass filter. Due to its direct relation to the ideal low-pass, it is neither causal nor stable. The ideal band-pass can only be approximated in practical realizations. Its plays an important role in the theoretical foundations of wireless communications.

**Example**

For illustration, the impulse response of the ideal band-pass for $\omega_\text{c} = 10$ and $\Delta \omega = 2$ is plotted

```python
wc = 10
dw = 2

h = sym.pi*dw * sym.sinc(dw/2*t) * sym.cos(wc*t)
sym.plot(h, (t, -10, 10), xlabel='$t$', ylabel='$h(t)$');
```

**Exercise**

* In the same manner as for the low-pass, derive the impulse response and transfer function of a realizable band-pass.

### Ideal High-Pass

The transfer function $H(j \omega)$ of a real-valued ideal high-pass reads

\begin{equation}
H(j \omega) = 1 - \text{rect} \left( \frac{\omega}{2 \omega_\text{c}} \right)
\end{equation}

where $\omega_\text{c} > 0$ denotes its cut-off frequency. The ideal high-pass removes all frequency components below the cut-off frequency $\omega_\text{c}$, without affecting higher frequencies. Its impulse response can be derived in a straightforward manner from the impulse response of the ideal low-pass

\begin{equation}
h(t) = \delta(t) - \frac{\omega_\text{c}}{\pi} \cdot \text{sinc} ( \omega_\text{c} t )
\end{equation}

Due to its relation to the ideal low-pass, the ideal high-pass is neither causal nor stable. The ideal high-pass can only be approximated in practical realizations.

### Ideal Band-Stop

The transfer function $H(j \omega)$ of a real-valued ideal band-stop is derived from the transfer function of the ideal band-pass in the same manner as the ideal high-pass. It reads

\begin{equation}
H(j \omega) =  1 - \text{rect} \left( \frac{\omega - \omega_\text{c}}{\Delta \omega} \right) - \text{rect} \left( \frac{\omega + \omega_\text{c}}{\Delta \omega} \right)
\end{equation}

The ideal band-stop removes the frequency components of a signal around a given center frequency $\omega_\text{c}$ where the total width of this stop band is $\Delta \omega$. Components outside the stop band are not affected by the system.  The impulse response of the ideal band-stop can be derived in a straightforward manner from the impulse response of the ideal band-pass as

\begin{equation}
h(t) = \delta(t) - \pi \Delta \omega \cdot \text{sinc} ( \frac{\Delta \omega}{2} t ) \cdot \cos(\omega_\text{c} t)
\end{equation}

Due to its relation to the ideal band-pass, the ideal band-stop is neither causal nor stable. The ideal band-stop can only be approximated in practical realizations. The ideal band-stop is for instance used to remove undesired signal components, e.g. [mains hum](https://en.wikipedia.org/wiki/Mains_hum).

**Copyright**

This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources). Feel free to use the notebook for your own purposes. The text is licensed under [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/), the code of the IPython examples under the [MIT license](https://opensource.org/licenses/MIT). Please attribute the work as follows: *Sascha Spors, Continuous- and Discrete-Time Signals and Systems - Theory and Computational Examples*.