Mathematica® i język programowania Wolfram Language

Do tej pory, aby zrealizować jakieś zadanie przy pomocy programu Mathematica, wystarczała nam prosta sekwencja instrukcji. Niekiedy jednak musimy sprawdzić, czy spełniony jest jakiś warunek lub wykonać wielokrotnie ten sam ciąg instrukcji. Warto też poznać sposoby na grupowanie instrukcji, które realizują odrębne zadania i stanowić mogą “cegiełkę” przydatną w wielu notatnikach.
Zrozumienie bardziej skomplikowanych notatników, choćby tych ze strony Wolfram Demonstration Project, wymaga poznania instrukcji warunkowych, pętli, budowania modułów itp.

ClearAll["Global`*"]

Instrukcje warunkowe

If [warunek, gdy_warunek_prawdziwy, gdy_warunek_fałszywy, gdy_warunek_nieokreślony]

Przykład 1: bardzo prosty

a=1; If[a > 0,Print["a > 0"], Print["a ≤ 0"]];

a=-2; If[a > 0,Print["a > 0"], Print["a ≤ 0"]];

a=0; If[a > 0,Print["a > 0"], Print["a ≤ 0"]];

Przykład 2: warunek nieokreślony

Clear[a]; (* wartość a staje się nieokreślona *)

If[a > 0,Print["a > 0"], Print["a ≤ 0"],Print["nie wiadomo, jaki a ma znak"]];

ClearAll["Global`*"]

Przykład 3: warunek w warunku

a=0;

If[a > 0,Print["a > 0"], If[a<0, Print["a < 0"], Print["a = 0"]]]

ClearAll["Global`*"]

Przykład 4: funkcja zbudowana z If:

Permutations[{1,2,3}]

Signature[{1,3,2}]

eps[i_,j_,k_]:=If[{i,j,k}!={1,2,3}&&{i,j,k}!={1,3,2}&&{i,j,k}!={2,1,3}&&{i,j,k}!={2,3,1}&&{i,j,k}!={3,1,2}&&{i,j,k}!={3,2,1},0,Signature[{i,j,k}]]

eps[1,2,3]

eps[1,3,2]

eps[0,1,2]

ClearAll["Global`*"]

Przykład 5: jeszcze większe zagęszczenie instrukcji If. 
Rozważamy rzeczywiste rozwiązania równania   a*(x^2)+ b*x + c = 0 dla dowolnych liczb rzeczywistych a, b i c:

a=0;b=0;c=-1;

Δ=b*b-4*a*c;
If[a≠0&&Δ≥0,x1=(-b-Sqrt[Δ])/(2*a);x2=(-b+Sqrt[Δ])/(2*a);
Print[" równanie kwadratowe:  a= ",a,", b= ",b,", c= ",c];
Print[" x1= ",x1,", x2= ",x2];,
If[a==0,
If[b≠0,
x1=-c/b;
Print[" równanie liniowe:  a= ",a,", b= ",b,", c= ",c];
Print[" x1= ",x1];,
If[c≠0,
Print[" a= ",a,", b= ",b,", c= ",c];Print[" sprzeczność "];,
Print[" a= ",a,", b= ",b,", c= ",c];
Print[" tożsamość: 0 == 0"];
]],
If[Δ<0,Print[" a= ",a,", b= ",b,", c= ",c];
Print[" Δ= ",Δ];
Print[" brak rozwiązań rzeczywistych "];]
]
]

ClearAll["Global`*"]

Which[ warunek1, wartość1, warunek2, wartość2, ... ]
obliczane są po kolei warunek1, warunek2 itd. i zwracana jest 
wartość odpowiadająca pierwszemu prawdziwemu warunkowi

Przykład 1: bardzo prosty

a=2;z=Which[a==1,x,a==2,y];

(* Which jest używane na przykład w instrukcji przypisania *)

z

(* Uwaga: Which przestaje być sprawdzane, jeśli któryś z warunków nie może być sprawdzony *)

ClearAll["Global`*"]

Przykład 2: jeden z warunków jest nieokreślony

a=3;Which[a==1,x,a==2,y,b==5,17,a==3,z]

ClearAll["Global`*"]

Przykład 3: żaden z warunków nie jest prawdziwy, ale nie dostajemy o tym informacji

a=5;Which[a==1,x,a==2,y,a==3,z]

ClearAll["Global`*"]

Przykład 4: jeśli chcemy mieć informację, że żaden z warunków nie jest prawdziwy, na koniec wstawiamy warunek trywialnie prawdziwy:

a=5;Which[a==1,x,a==2,y,a==3,z,0<1,Print["nic nie wybrano !"]]

Switch[ wyrażenie, wartość1, wynik1, wartość2, wynik2, ... ]
obliczane jest wyrażenie, a potem jest porównywane po kolei z wartość1, wartość2, ... . Zwracany jest wynik, odpowiadający pierwszemu trafieniu w wartość wyrażenia

ClearAll["Global`*"]

Przykład 1: Switch daje wynik  +2 dla liczy parzystej oraz  -2 dla liczby nieparzystej:

x=3;Switch[Mod[x,2],0,2,1,-2]

x=44;Switch[Mod[x,2],0,2,1,-2]

ClearAll["Global`*"]

Przykład 2: Wynik Switch, gdy liczba nie jest ani parzysta, ani nieparzysta:

x=3/2;Switch[Mod[x,2],0,2,1,-2]

Przykład 3: Zabezpieczenie, na wypadek, gdy nie ma trafienia w żadną wartość:

x=3/2;Switch[Mod[x,2],0,2,1,-2,_,0]

Piecewise [ { {wyniki1, warunek1}, {wynik2,warunek2}, ...}]
lub
Piecewise [ { {wyniki1, warunek1}, {wynik2,warunek2}, ...}, wynik0 ]
Służy do zdefiniowania funkcji określonej odrębnymi wzorami w różnych przedziałach

ClearAll["Global`*"]

Przykład 1: gładkie sklejenie dwóch funkcji liniowych i cosinusa:

f[x_]:=Piecewise[{{x+Pi/2,x≤-Pi/2},{Cos[x],-Pi/2<x≤Pi/2},{-x+Pi/2,x>Pi/2}}]

Plot[f[x],{x,-3,3}]

Plot[f'[x],{x,-3,3}]

ClearAll["Global`*"]

Przykład 2: wykorzystana jest wartość obowiązująca poza zdefiniowanymi przypadkami:

f[x_]:=Piecewise[{{x^2,-Sqrt[3]≤ x≤2},{-x+6,2<x≤3}},3]

Plot[f[x],{x,-3,5}]

ClearAll["Global`*"]

Instrukcje iteracyjne (pętle)

Do [co_robimy, {licznik, początek, koniec, zmiana_licznika}]

Przykład 1: pętla z ustalonym zakresem i krokiem

Do[Print[i!],{i,1,10,2}]

i

(* Wartość i po wykonaniu pętli jest nieokreślona ! *)

Przykład 2: pętla z zadanymi wartościami

Do[Print[i!],{i,{1,3,4,6,11,12}}]

Przykład 3: pętla podwójna wypisuje wszystkie liczby dwucyfrowe, które są kwadratami. Uwaga: szybciej zmienia się j

Do[If[Mod[i*10+j,Sqrt[i*10+j]]==0,Print["i= ",i,",  j= ",j,",   ",i*10+j]],{i,1,9},{j,0,9}]

i

j

ClearAll["Global`*"]

For [początek, warunek, zmiana_licznika, co_robimy]

Przykład 1: pętla z ustalonym zakresem i krokiem

For[i=1,i<10,i=i+2,Print[i!]]

i

(* Uwaga: wartość i jest określona ! *)

ClearAll["Global`*"]

Przykład 2: pętla podwójna wypisuje wszystkie liczby dwucyfrowe, które są kwadratami. Uwaga: szybciej zmienia się j

For[i=1,i<10,i=i+1,For[j=0,j<10,j++,If[Mod[i*10+j,Sqrt[i*10+j]]==0,Print["i= ",i,",  j= ",j,",   ",i*10+j]]]]

i

j

ClearAll["Global`*"]

While [warunek, co_robimy]

Przykład 1: pętla z ustalonym zakresem i krokiem

i=1; While[i<10,Print[i!];i=i+2]

i

(* Uwaga: wartość i jest określona *)

ClearAll["Global`*"]

i=1;While[i<10,j=0;While[j<10,If[Mod[i*10+j,Sqrt[i*10+j]]==0,Print["i= ",i,",  j= ",j,",   ",i*10+j]];j++];
i++]

i

j

ClearAll["Global`*"]

Break [ ] (wcześniejsze zakończenie pętli)

Przykład 0: pełna pętla

For[i=1,i<10,i=i+2,Print[i!]]

Przykład 1: pętla pojedyncza z Break

For[i=1,i<10,i=i+2,If[i!>1000,Break[]];Print[i!]]

Przykład 2: pętla podwójna
Jak w tym wypadku zachowa się Break stosowane w wewnętrznej pętli ?

i=.;

Reduce[i! == 5040,i,Integers]

For[j=1,j<4,j++,Print[" pętla zewnętrzna: j= ",j];For[i=1,i<10,i=i+2,If[i!==120||i!==5040,Break[]];Print[i!]]]

(* Uwaga: przerwanie zachodzi tylko w wewnętrznej pętli ! *)

ClearAll["Global`*"]

Continue[ ] (opuszczenie elementu lub elementów pętli)

Przykład 1: pętla pojedyncza

For[i=1,i<10,i=i+2,If[i!==120||i!==5040,Continue[]];Print[i!]]

Przykład 2: pętla podwójna

For[j=1,j<4,j++,Print[" pętla zewnętrzna: j= ",j];For[i=1,i<10,i=i+2,If[i!==120||i!==5040,Continue[]];Print[i!]]]

(* Uwaga: opuszczenie zachodzi tylko w wewnętrznej pętli *)

ClearAll["Global`*"]

Goto [etykieta ] (skok)
Instrukcja z gatunku “używać w ostateczności”

Przykład 1: przerwanie wykonywania pętli podwójnej odbywające się wewnątrz wydzielonej grupy instrukcji (w tzw. module, o którym będzie mowa później)

Module[{i,j},For[j=1,j<4,j++,Print[" pętla zewnętrzna: j= ",j];For[i=1,i<10,i=i+2,Print[" pętla wewnętrzna: i= ",i];If[i!==120||i!==5040,Goto[end]];Print[i!]]];
Label[end];Print[" W module, ale poza pętlą !"];
Print[" i,j= ",i,", ",j];]

(* Teraz jestem poza modułem *)

i

j

(* Skok zakończył działanie podwójnej pętli  *)

(* Ważne: poza modułem wartości i oraz j nie są określone ! *)

Przykład 2: skok wewnątrz tzw. procedury, czyli wewnątrz grupy instrukcji

(q=2;Label[begin];Print[q];q=q+3;If[q<6,Goto[begin]])

Grupowanie instrukcji

ClearAll["Global`*"]

With (oblicz, podstawiając ...)

With[{y=5+Sqrt[2]},Simplify[y^3+2]]

(* Ważne: zmienna y pozostaje nieokreslona *)

y

(* Można użyć With do stworzenia prostej funkcji (Wolfram) *)

f[x_]:=With[{y=x+1},1+y+y^2]

f[3]

(* Typowe zadanie: Narysować wykres funkcji sin(|x-1|)+(1/100)(((x+1))^2) w przedziale [0,2π] *)

g[x_]:=With[{y=Abs[x-1],z=x+1},Sin[y]+z^2/100]

Plot[g[x],{x,0,2Pi}]

ClearAll["Global`*"]

Block[ {x, y, …}, instrukcje]	
wykonuje instrukcje, używając lokalnych wartości dla x, y, …

Block[ {x=x0, y=y0,…}, instrukcje]
wykonuje instrukcje, przypisując początkowe wartości zmiennym  x, y, …

x=4;y=5;

Block[{x,y},x=1;x+y^2]

x

y

(* Czyli Block zna wcześniejsze wartości zmiennych x i y, może je lokalnie zmienić, ale po zakończeniu działania tej instrukcji wartości x i y są takie same, jak przed użyciem Block *)

ClearAll["Global`*"]

Module[ {x, y, …}, instrukcje]	
wykonuje instrukcje, traktując x, y, ... jako wielkości istniejące tylko lokalnie 

Module[ {x=x0, y=y0,…}, wyrażenie]
wykonuje instrukcje, przypisując początkowe wartości zmiennym  x, y, …

x=4;y=5;

Module[{x,y},x=1;Print["x= ",x,",  y= ",y];x+y^2]

(* Wielkość y używana przed wywołaniem Module, nie jest widoczna w Module i nie została w Module zdefiniowana! Wartość zmiennej x została zmieniona tylko LOKALNIE. Po zakończeniu instrukcji Module znana jest tylko wartość nadana przed wywołaniem modułu. *)

x

y

(* Tu przypisuję wartości początkowe zmiennym lokalnym x i y, a potem jedną z nich zmieniam. *)

Module[{x=1,y=3},x=x+1;Print["x= ",x,",  y= ",y];x+y^2]

x

y

(* Moduł może dać wynik, tak jak funkcja. *)

z=Module[{x,y},x=1;y=3;x+y^2];

z

ClearAll["Global`*"]

Przykład 1 (Wolfram) Moduł może stanowić zasadniczą część rozbudowanej funkcji.

f[x0_]:=
Module[{x=x0},
While[x>0,x=Log[x]];
x] (* Uwaga: po x nie może być średnika ! *)

f[2.0]

x (* ta zmienna nie jest określona poza modułem *)

Przykład 2: To samo, co poprzednio z jawnym zaznaczeniem (poprzez Return), co ma być wartością funkcji

f[x0_]:=
Module[{x=x0},
While[x>0,x=Log[x]];
Return[x];]

f[2.0]

x

Przykład 3: Moduł, z podanych dwóch punktów na płaszczyźnie, liczy współczynniki a i b w równaniu kierunkowym prostej y == a*x + b, a więc jako wynik podaje “coś więcej” niż pojedynczą liczbę !  Nie sprawdza, czy punkty nie leżą jeden nad drugim !

wspab[rA_,rB_]:=Module[{xA=rA[[1]],yA=rA[[2]],xB=rB[[1]],yB=rB[[2]],a,b},sab=Solve[{yA==a*xA+b,yB==a*xB+b},{a,b}];a=a/.sab[[1]];b=b/.sab[[1]];{a,b}]

wspab[{1,2},{2,3}]

Przykład 3.1 : Moduł, z podanych dwóch punktów na płaszczyźnie, liczy równanie kierunkowe prostej y == a*x + b, jeśli punkty nie leżą jeden nad drugim, a w przeciwnym wypadku podaje równanie w postaci x== const.
Zasadnicza część jest kopią poprzedniego modułu.

RownanieProstej[rA_,rB_]:=Module[{xA=rA[[1]],yA=rA[[2]],xB=rB[[1]],yB=rB[[2]],a,b},If[xA≠ xB,sab=Solve[{yA==a*xA+b,yB==a*xB+b},{a,b}];a=a/.sab[[1]];b=b/.sab[[1]];y==a*x+b,x==xA]]

RownanieProstej[{1,2},{2,3}]

RownanieProstej[{1,2},{1,3}]

ClearAll["Global`*"]

Przykład: (JG & Co.) Moduł realizuje algorytm tzw. sortowania bąbelkowego jednowymiarowej tablicy,
zwracając nie tylko posortowaną tablicę, ale także jej element najmniejszy i największy.

BSort[X_]:=Module[{n=Length[X],tmp,i,j,X1=X},
For[i=1,i≤ n,i++,
For[j = 1, j<n-i+1,j++,
If[ X1[[j]]>X1[[j+1]],
{tmp = X1[[j+1]],
X1[[j+1]]=X1[[j]],
X1[[j]] = tmp}
]]];
Xmin = X1[[1]];
Xmax = X1[[n]];
{X1,X1[[1]],X1[[n]]}
]

S= {1,3,5,2,5,7,1,2,56,1,1};

BSort[S]

Sort[S]

Ssort=First@BSort[S]

Smin=BSort[S][[2]]

Smax=BSort[S][[3]]

(* Oczywiście mogę ten moduł zastosować do sortowania zupełnie innej tablicy *)

BSort[{1,-1,3,-5}]

ClearAll["Global`*"]

Function[ {x, y, …}, instrukcje]	
Tzw. czysta funkcja, która ma formalne parametry x, y, …

(* Przykład 1: funkcja przyjmuje dwa argumenty i liczy z nich proste wyrażenie  *)

f=Function[{u,v},u^2+v^4]

f[x,y]

f[1,2]

(* Można od razu tak, bez definiowania f *)

Function[{u,v},u^2+v^4][1,2]

(* Przykład 2: czysta funkcja korzysta z wcześniej zdefiniowanych obiektów, może je modyfikować (h), a także definiować nowe obiekty (z)   *)

h=3;

Function[{u,v},h=h+1;z=u+v;z^2+(v+h)^4][x,y]

h

z

(* Przykład 2: więcej się dzieje w funkcji *)

vt1=Function[{r,t,t1},(v=D[r,t])/.{t->t1}];

(* vt1 ma liczyć na podstawie ogólnego wzoru na położenie punktu materialnego w chwili t, jego prędkość w chwili t=t1 *)

vt1[{2*t+3,-4*t,t^2},t,3]

vt1[{2-u,4-2*u,-u^2},u,2]

(* Ta funkcja działa także w jednym wymiarze ... *)

vt1[5*t,t,3]

(* ... i w dwóch wymiarach *)

vt1[{5*t,t^2},t,t1]

ClearAll["Global`*"]

(* Przykład 3 *)

Niekiedy zdefiniowanie funkcji (szerzej tzw. operatora) musi obejmować połączenie różnych operacji takich jak mnożenie macierzowe i liczenie pochodnych względem różnych zmiennych. W takich przypadkach “czysta funkcja” bardzo się przydaje !
Jako przykład podaję działanie tzw. hamiltonianu Diraca, 

który jest zasadniczą częścią słynnego równania Diraca:

(https://www.wikiwand.com/pl/R%C3%B3wnanie_Diraca)
Hamiltonian Diraca oznaczać będę skrótem HDirac. Aby zdefiniować HDirac potrzebuję kilku macierzy:

beta=(({{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, -1, 0}, {0, 0, 0, -1}}));

alfa[1]=(({{0, 0, 0, 1}, {0, 0, 1, 0}, {0, 1, 0, 0}, {1, 0, 0, 0}}));

alfa[2]=(({{0, 0, 0, -I}, {0, 0, I, 0}, {0, -I, 0, 0}, {I, 0, 0, 0}}));

alfa[3]=(({{0, 0, 1, 0}, {0, 0, 0, -1}, {1, 0, 0, 0}, {0, -1, 0, 0}}));

Na co działa hamiltonian Diraca ? Na funkcję ψ, która ma cztery składowe (ψ1, ψ2, ψ3 i ψ4) zależne od czterech zmiennych t, x, y i z

ψ[t_,x_,y_,z_]:={ψ1[t,x,y,z],ψ2[t,x,y,z],ψ3[t,x,y,z],ψ4[t,x,y,z]};

MatrixForm[ψ[t,x,y,z]]

Jak działa hamiltonian Diraca ?

HDirac=Function[{f,t,x,y,z},-I*alfa[1].D[f,x]-I*alfa[2].D[f,y]-I*alfa[3].D[f,z]+m*beta.f];

W szczególności alfa[1].D[f, x] oznacza, że każdy element czteroelementowego wektora f zostanie zróżniczkowany po x, a następnie wektor wynikowy zostanie pomnożony przez macierz -I*alfa[1]. W HDirac są trzy składniki tego typu; czwarty to zwykłe mnożenie macierzowe przez macierz m*beta, gdzie m jest masą cząstki np. elektronu.

HDirac[ψ[t,x,y,z],t,x,y,z]

Przypominam definicję zapisu stosowanego przez program Mathematica

Derivative[0,0,1,0][ψ1][t,x,y,z]== D[ψ1[t,x,y,z],y]

MatrixForm[HDirac[ψ[t,x,y,z],t,x,y,z]]

Hamiltonian Dirac nie tylko zawiera liczenie pochodnych, ale także “mieszanie” składowych ψ !

Tego mieszania składowych NIE MA przy dwukrotnym zadziałaniu HDirac na wektor ψ=(ψ1, ψ2, ψ3 i ψ4) !

MatrixForm[Simplify[HDirac[HDirac[ψ[t,x,y,z],t,x,y,z],t,x,y,z]]]

(* W wierszu i pojawia się tylko ψi[t,x,y,z] i jej pochodne *)

ClearAll["Global`*"]

Grupa instrukcji (ujętych w nawias), które mają na celu konkretne zadanie

Przykład: procedura, której argumentem jest nazwa pliku z danymi liczbowymi (parami liczb (xi, yi)). Wyodrębniona grupa instrukcji ujętych w nawiasy realizuje schemat tzw. regresji klasycznej. Uwaga: wynikiem procedury jest ostatnio policzone wyrażenie !

Regresja1[plik_]:=(
XY=ReadList[NotebookDirectory[]<>plik,{Number,Number}];
n = Length[XY];
X=Table[XY[[i]][[1]],{i,1,n}];
Y=Table[XY[[i]][[2]],{i,1,n}];
c=n*X.X-Total[X]^2;
d=n*Y.Y-Total[Y]^2;
a=(n*X.Y-Total[X]*Total[Y])/c;
b=(Total[Y]-a*Total[X])/n;
Sa=Sqrt[n*(Y.Y-a*X.Y-b*Total[Y])/((n-2)*c)];
Sb=Sa*Sqrt[X.X/n];
r=(n*X.Y-Total[X]*Total[Y])/Sqrt[c*d];
Print["a ma wartość ",a," z niepewnością ",Sa];Print["b ma wartość ",b," z niepewnością ",Sb];
Print["Współczynnik korelacji ma wartość ", r];
offset=(Max[X]-Min[X])/20;
Show[ListPlot[XY],Plot[a x+b,{x,Min[X]-offset,Max[X]+offset}]])

Regresja1["dane.txt"]

ClearAll["Global`*"]

(* teraz inna wersja, gdzie pisanie przesunięto poza procedurę *)

z=17;

n=1;

Regresja2[plik_]:=(
z=21;
XY=ReadList[NotebookDirectory[]<>plik,{Number,Number}];
n = Length[XY];
X=Table[XY[[i]][[1]],{i,1,n}];
offset=(Max[X]-Min[X])/20;
Y=Table[XY[[i]][[2]],{i,1,n}];
c=n*X.X-Total[X]^2;
d=n*Y.Y-Total[Y]^2;
a=(n*X.Y-Total[X]*Total[Y])/c;
b=(Total[Y]-a*Total[X])/n;
Sa=Sqrt[n*(Y.Y-a*X.Y-b*Total[Y])/((n-2)*c)];
Sb=Sa*Sqrt[X.X/n];
r=(n*X.Y-Total[X]*Total[Y])/Sqrt[c*d];
)

Regresja2["dane.txt"]

Print["a ma wartość ",a," z niepewnością ",Sa];

Print["b ma wartość ",b," z niepewnością ",Sb];

Print["Współczynnik korelacji ma wartość ", r];

Show[ListPlot[XY],Plot[a x+b,{x,Min[X]-offset,Max[X]+offset}]]

z

n

(* Wniosek: wyniki instrukcji zgrupowanych w nawiasach mogą zależeć od wcześniejszych wartości zmiennych i są zmieniane nie tylko lokalnie ! *)

ClearAll["Global`*"]

(* Trzecia wersja procedury, z wyraźnie wyodrębnionym wynikiem w postaci listy. Uwaga na brak średnika po nawiasie kończącym listę ! *)

Regresja3[plik_]:=(
XY=ReadList[NotebookDirectory[]<>plik,{Number,Number}];
n = Length[XY];
X=Table[XY[[i]][[1]],{i,1,n}];
offset=(Max[X]-Min[X])/20;
Y=Table[XY[[i]][[2]],{i,1,n}];
c=n*X.X-Total[X]^2;
d=n*Y.Y-Total[Y]^2;
a=(n*X.Y-Total[X]*Total[Y])/c;
b=(Total[Y]-a*Total[X])/n;
Sa=Sqrt[n*(Y.Y-a*X.Y-b*Total[Y])/((n-2)*c)];
Sb=Sa*Sqrt[X.X/n];
r=(n*X.Y-Total[X]*Total[Y])/Sqrt[c*d]; 
{a,Sa,b,Sb,r}
)

Regresja3["dane.txt"]

Regresja3["dane.txt"][[1]]

Regresja3["dane.txt"][[2]]

Regresja3["dane.txt"][[3]]

Regresja3["dane.txt"][[4]]

Regresja3["dane.txt"][[5]]

a

b

Print["a ma wartość ",a," z niepewnością ",Sa];

Print["b ma wartość ",b," z niepewnością ",Sb];

Print["Współczynnik korelacji ma wartość ", r];

XY

Show[ListPlot[XY],Plot[a x+b,{x,Min[X]-offset,Max[X]+offset}]]

n

X

(* Wniosek: wyniki mogą być też dostępne w postaci listy ! *)

Y