mirror of
https://github.com/fverdugo/XM_40017.git
synced 2026-11-15 02:37:17 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cae58c2e7 | ||
|
|
ae6e14bc62 | ||
|
|
aa1b5ce0d7 | ||
|
|
74b41c059e | ||
|
|
388a8d9f5a | ||
|
|
50cb8fff17 | ||
|
|
470bb36cc6 | ||
|
|
072476ec46 | ||
|
|
4f4b7fa430 | ||
|
|
20c92dc92b | ||
|
|
82cfa1d44b | ||
|
|
024429bceb | ||
|
|
5835451687 | ||
|
|
e4eea0da0a | ||
|
|
08cfd87856 |
No files matched your search
@@ -210,11 +210,11 @@ To install a package, we need to enter *package* mode. Remember that we entered
|
||||
```julia
|
||||
julia> ]
|
||||
```
|
||||
At this point, the prompt should have changed to `(@v1.10) pkg>` indicating that we are in package mode. The text between the parentheses indicates which is the active *project*, i.e., where packages are going to be installed. In this case, we are working with the global project associated with our Julia installation (which is Julia 1.10 in this example, but it can be another version in your case).
|
||||
At this point, the prompt should have changed to `(@v1.11) pkg>` indicating that we are in package mode. The text between the parentheses indicates which is the active *project*, i.e., where packages are going to be installed. In this case, we are working with the global project associated with our Julia installation (which is Julia 1.11 in this example, but it can be another version in your case).
|
||||
|
||||
To install the MPI package, type
|
||||
```julia
|
||||
(@v1.10) pkg> add MPI
|
||||
(@v1.11) pkg> add MPI
|
||||
```
|
||||
Congrats, you have installed MPI!
|
||||
|
||||
@@ -222,7 +222,8 @@ Congrats, you have installed MPI!
|
||||
Many Julia package names end with `.jl`. This is just a way of signaling that a package is written in Julia. When using such packages, the `.jl` needs to be omitted. In this case, we have installed the `MPI.jl` package even though we have only typed `MPI` in the REPL.
|
||||
|
||||
!!! note
|
||||
The package you have installed is the Julia interface to MPI, called `MPI.jl`. Note that it is not a MPI library by itself. It is just a thin wrapper between MPI and Julia. To use this interface, you need an actual MPI library installed in your system such as OpenMPI or MPICH. Julia downloads and installs a MPI library for you, but it is also possible to use a MPI library already available in your system. This is useful, e.g., when running on HPC clusters. See the [documentation](https://juliaparallel.org/MPI.jl/stable/configuration/) of `MPI.jl` for further details.
|
||||
The package you have installed is the Julia interface to MPI, called `MPI.jl`. Note that it is not an MPI library by itself. It is just a thin wrapper between MPI and Julia. To use this interface, you need an actual MPI library installed in your system such as OpenMPI or MPICH. Julia downloads and installs an MPI library for you, but it is also possible to use an MPI library already available in your system. This is useful, e.g., when running on HPC clusters. See the [documentation](https://juliaparallel.org/MPI.jl/stable/configuration/) of `MPI.jl` for further details.
|
||||
|
||||
|
||||
To check that the package was installed properly, exit package mode by pressing the backspace key several times, and run it again
|
||||
|
||||
@@ -241,7 +242,7 @@ $ mpiexec -np 4 julia hello_mpi.jl
|
||||
But it will probably not work since the version of `mpiexec` needs to match with the MPI version we are using from Julia. Don't worry if you could not make it work! A more elegant way to run MPI code is from the Julia REPL directly, by using these commands:
|
||||
```julia
|
||||
julia> using MPI
|
||||
julia> run(`$(mpiexec()) -np 4 julia hello_mpi.jl`)
|
||||
julia> run(`$(mpiexec()) -np 4 julia hello_mpi.jl`);
|
||||
```
|
||||
|
||||
Now, you should see output from 4 ranks.
|
||||
@@ -254,7 +255,7 @@ We have installed the `MPI` package globally and it will be available in all Jul
|
||||
|
||||
A project is simply a folder in your file system. To use a particular folder as your project, you need to *activate* it. This is done by entering package mode and using the `activate` command followed by the path to the folder you want to activate.
|
||||
```julia
|
||||
(@v1.10) pkg> activate .
|
||||
(@v1.11) pkg> activate .
|
||||
```
|
||||
The previous command will activate the current working directory. Note that the dot `.` is indeed the path to the current folder.
|
||||
|
||||
@@ -264,7 +265,7 @@ The prompt has changed to `(lessons) pkg>` indicating that we are in the project
|
||||
You can activate a project directly when opening Julia from the terminal using the `--project` flag. The command `$ julia --project=.` will open Julia and activate a project in the current directory. You can also achieve the same effect by setting the environment variable `JULIA_PROJECT` with the path of the folder you want to activate.
|
||||
|
||||
!!! note
|
||||
The active project folder and the current working directory are two independent concepts! For instance, `(@v1.10) pkg> activate folderB` and then `julia> cd("folderA")`, will activate the project in `folderB` and change the current working directory to `folderA`.
|
||||
The active project folder and the current working directory are two independent concepts! For instance, `(@v1.11) pkg> activate folderB` and then `julia> cd("folderA")`, will activate the project in `folderB` and change the current working directory to `folderA`.
|
||||
|
||||
At this point all package-related operations will be local to the new project. For instance, install the `DataFrames` package.
|
||||
|
||||
@@ -282,7 +283,7 @@ Now, we can return to the global project to check that `DataFrames` has not been
|
||||
```julia
|
||||
(lessons) pkg> activate
|
||||
```
|
||||
The prompt is again `(@v1.10) pkg>`
|
||||
The prompt is again `(@v1.11) pkg>`
|
||||
|
||||
Now, try to use `DataFrames`.
|
||||
|
||||
@@ -306,13 +307,13 @@ In other words, `Project.toml` contains the packages relevant for the user, wher
|
||||
You can see the path to the current `Project.toml` file by using the `status` operator (or `st` in its short form) while in package mode
|
||||
|
||||
```julia
|
||||
(@v1.10) pkg> status
|
||||
(@v1.11) pkg> status
|
||||
```
|
||||
|
||||
The information about the `Manifest.toml` can be inspected by passing the `-m` flag.
|
||||
|
||||
```julia
|
||||
(@v1.10) pkg> status -m
|
||||
(@v1.11) pkg> status -m
|
||||
```
|
||||
|
||||
### Installing packages from a project file
|
||||
@@ -336,7 +337,7 @@ julia> mkdir("newproject")
|
||||
|
||||
To install all the packages registered in this file you need to activate the folder containing your `Project.toml` file
|
||||
```julia
|
||||
(@v1.10) pkg> activate newproject
|
||||
(@v1.11) pkg> activate newproject
|
||||
```
|
||||
and then *instantiating* it
|
||||
```julia
|
||||
@@ -350,12 +351,12 @@ The instantiate command will download and install all listed packages and their
|
||||
You can get help about a particular package operator by writing `help` in front of it
|
||||
|
||||
```julia
|
||||
(@v1.10) pkg> help activate
|
||||
(@v1.11) pkg> help activate
|
||||
```
|
||||
|
||||
You can get an overview of all package commands by typing `help` alone
|
||||
```julia
|
||||
(@v1.10) pkg> help
|
||||
(@v1.11) pkg> help
|
||||
```
|
||||
|
||||
### Package operations in Julia code
|
||||
@@ -368,7 +369,7 @@ julia> Pkg.status()
|
||||
```
|
||||
is equivalent to calling `status` in package mode.
|
||||
```julia
|
||||
(@v1.10) pkg> status
|
||||
(@v1.11) pkg> status
|
||||
```
|
||||
|
||||
### Creating you own package
|
||||
@@ -379,7 +380,7 @@ or if you want to eventually [register your package](https://github.com/JuliaReg
|
||||
The simplest way of generating a package (called `MyPackage`) is as follows. Open Julia, go to package mode, and type
|
||||
|
||||
```julia
|
||||
(@v1.10) pkg> generate MyPackage
|
||||
(@v1.11) pkg> generate MyPackage
|
||||
```
|
||||
|
||||
This will crate a minimal package consisting of a new folder `MyPackage` with two files:
|
||||
@@ -389,13 +390,13 @@ This will crate a minimal package consisting of a new folder `MyPackage` with tw
|
||||
|
||||
!!! tip
|
||||
This approach only generates a very minimal package. To create a more sophisticated package skeleton (including unit testing, code coverage, readme file, licence, etc.) use
|
||||
[`PkgTemplates.jl`](https://github.com/JuliaCI/PkgTemplates.jl) or [`BestieTemplate.jl`](https://github.com/abelsiqueira/BestieTemplate.jl). The later one is developed in Amsterdam at the
|
||||
[`PkgTemplates.jl`](https://github.com/JuliaCI/PkgTemplates.jl) or [`BestieTemplate.jl`](https://github.com/JuliaBesties/BestieTemplate.jl). The later one is developed in Amsterdam at the
|
||||
[Netherlands eScience Center](https://www.esciencecenter.nl/).
|
||||
|
||||
You can add dependencies to the package by activating the `MyPackage` folder in package mode and adding new dependencies as always:
|
||||
|
||||
```julia
|
||||
(@v1.10) pkg> activate MyPackage
|
||||
(@v1.11) pkg> activate MyPackage
|
||||
(MyPackage) pkg> add MPI
|
||||
```
|
||||
|
||||
@@ -406,7 +407,7 @@ This will add MPI to your package dependencies.
|
||||
To use your package you first need to add it to a package environment of your choice. This is done by changing to package mode and typing `develop ` followed by the path to the folder containing the package. For instance:
|
||||
|
||||
```julia
|
||||
(@v1.10) pkg> develop MyPackage
|
||||
(@v1.11) pkg> develop MyPackage
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ Welcome to the interactive lecture notes of the [Programming Large-Scale Paralle
|
||||
This page contains part of the course material of the Programming Large-Scale Parallel Systems course at VU Amsterdam.
|
||||
We provide several lecture notes in jupyter notebook format, which will help you to learn how to design, analyze, and program parallel algorithms on multi-node computing systems.
|
||||
Further information about the course is found in the study guide
|
||||
([click here](https://studiegids.vu.nl/EN/courses/2023-2024/XM_40017#/)) and our Canvas page (for registered students).
|
||||
([click here](https://studiegids.vu.nl/en/vakken/2025-2026/XM_40017#/)) and our Canvas page (for registered students).
|
||||
|
||||
!!! note
|
||||
Material will be added incrementally to the website as the course advances.
|
||||
|
||||
@@ -27,12 +27,17 @@ ex2(f,g) = x -> f(x) + g(x)
|
||||
### Exercise 3
|
||||
|
||||
```julia
|
||||
using GLMakie
|
||||
max_iters = 100
|
||||
n = 1000
|
||||
x = LinRange(-1.7,0.7,n)
|
||||
y = LinRange(-1.2,1.2,n)
|
||||
heatmap(x,y,(i,j)->mandel(i,j,max_iters))
|
||||
values = zeros(n,n)
|
||||
for j in 1:n
|
||||
for i in 1:n
|
||||
values[i,j] = surprise(x[i],y[j])
|
||||
end
|
||||
end
|
||||
using GLMakie
|
||||
heatmap(x,y,values)
|
||||
```
|
||||
|
||||
## Asynchronous programming in Julia
|
||||
@@ -43,11 +48,12 @@ heatmap(x,y,(i,j)->mandel(i,j,max_iters))
|
||||
|
||||
```julia
|
||||
f = () -> Channel{Int}(1)
|
||||
chnls = [ RemoteChannel(f,w) for w in workers() ]
|
||||
@sync for (iw,w) in enumerate(workers())
|
||||
worker_ids = workers()
|
||||
chnls = [ RemoteChannel(f,w) for w in worker_ids ]
|
||||
@sync for (iw,w) in enumerate(worker_ids)
|
||||
@spawnat w begin
|
||||
chnl_snd = chnls[iw]
|
||||
if w == 2
|
||||
if iw == 1
|
||||
chnl_rcv = chnls[end]
|
||||
msg = 2
|
||||
println("msg = $msg")
|
||||
@@ -65,23 +71,26 @@ chnls = [ RemoteChannel(f,w) for w in workers() ]
|
||||
end
|
||||
```
|
||||
|
||||
This is another possible solution.
|
||||
This is another possible solution that does not use remote channels.
|
||||
|
||||
```julia
|
||||
@everywhere function work(msg)
|
||||
@everywhere function work(msg,iw,worker_ids)
|
||||
println("msg = $msg")
|
||||
if myid() != nprocs()
|
||||
next = myid() + 1
|
||||
@fetchfrom next work(msg+1)
|
||||
if iw < length(worker_ids)
|
||||
inext = iw+1
|
||||
next = worker_ids[iw+1]
|
||||
@fetchfrom next work(msg+1,inext,worker_ids)
|
||||
else
|
||||
@fetchfrom 2 println("msg = $msg")
|
||||
@fetchfrom worker_ids[1] println("msg = $msg")
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
msg = 2
|
||||
@fetchfrom 2 work(msg)
|
||||
iw = 1
|
||||
worker_ids = workers()
|
||||
@fetchfrom worker_ids[iw] work(msg,iw,worker_ids)
|
||||
```
|
||||
|
||||
|
||||
## Matrix-matrix multiplication
|
||||
|
||||
### Exercise 1
|
||||
|
||||
+6
-6
@@ -103,7 +103,7 @@
|
||||
"### Problem statement\n",
|
||||
"\n",
|
||||
"Let us consider a system of linear equations written in matrix form $Ax=b$, where $A$ is a nonsingular square matrix, and $x$ and $b$ are vectors. $A$ and $b$ are given, and $x$ is unknown. The goal of Gaussian elimination is to transform the system $Ax=b$, into a new system $Ux=c$ such that\n",
|
||||
"- both system have the same solution vector $x$,\n",
|
||||
"- both systems have the same solution vector $x$,\n",
|
||||
"- the matrix $U$ of the new system is *upper triangular* with unit diagonal, namely $U_{ii} = 1$ and $U_{ij} = 0$ for $i>j$.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -398,7 +398,7 @@
|
||||
"source": [
|
||||
"### Data partition\n",
|
||||
"\n",
|
||||
"Let start considering a row-wise block partition, as we did in previous algorithms.\n",
|
||||
"Let's start considering a row-wise block partition, as we did in previous algorithms.\n",
|
||||
"\n",
|
||||
"In the figure below, we use different colors to illustrate which entries are assigned to a CPU. All entries with the same color are assigned to the same CPU."
|
||||
]
|
||||
@@ -454,7 +454,7 @@
|
||||
"<b>Definition:</b> *Load imbalance*: is the problem when work is not equally distributed over all processes and consequently some processes do more work than others.\n",
|
||||
"</div>\n",
|
||||
"\n",
|
||||
"Having processors waiting for others is a waist of computational resources and affects negatively parallel speedups. The optimal speedup (speedup equal to the number of processors) assumes that the work is perfectly parallel and that it is evenly distributed. If there is load imbalance, the last assumption is not true anymore and the speedup will be suboptimal.\n"
|
||||
"Having processors waiting for others is a waste of computational resources and affects negatively parallel speedups. The optimal speedup (speedup equal to the number of processors) assumes that the work is perfectly parallel and that it is evenly distributed. If there is load imbalance, the last assumption is not true anymore and the speedup will be suboptimal.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -620,15 +620,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.9.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.9"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.9.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
+5
-5
@@ -57,7 +57,7 @@
|
||||
"function q1_answer(bool)\n",
|
||||
" bool || return\n",
|
||||
" msg = \"\"\"\n",
|
||||
" The we can change the loop order over i and j without changing the result. Rememeber:\n",
|
||||
" Then we can change the loop order over i and j without changing the result. Remember:\n",
|
||||
" \n",
|
||||
" C[i,j] = min(C[i,j],C[i,k]+C[k,j])\n",
|
||||
" \n",
|
||||
@@ -788,7 +788,7 @@
|
||||
" if rank == 0\n",
|
||||
" N = size(C,1)\n",
|
||||
" if mod(N,P) !=0\n",
|
||||
" println(\"N not multplie of P\")\n",
|
||||
" println(\"N not multiple of P\")\n",
|
||||
" MPI.Abort(comm,-1)\n",
|
||||
" end\n",
|
||||
" Nref = Ref(N)\n",
|
||||
@@ -1131,15 +1131,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.9.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.9"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.9.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
|
After Width: | Height: | Size: 440 KiB |
@@ -27,7 +27,7 @@
|
||||
"\n",
|
||||
"In this notebook, we will learn\n",
|
||||
"\n",
|
||||
"- How to paralleize the Jacobi method\n",
|
||||
"- How to parallelize the Jacobi method\n",
|
||||
"- How the data partition can impact the performance of a distributed algorithm\n",
|
||||
"- How to use latency hiding to improve parallel performance\n",
|
||||
"\n"
|
||||
@@ -452,7 +452,7 @@
|
||||
"- We need to get remote entries from 2 neighbors (2 messages per iteration)\n",
|
||||
"- We need to communicate 1 entry per message\n",
|
||||
"- Thus, communication complexity is $O(1)$\n",
|
||||
"- Communication/computation ration is $O(P/N)$, making the algorithm potentially scalable if $P<<N$.\n"
|
||||
"- Communication/computation ratio is $O(P/N)$, making the algorithm potentially scalable if $P<<N$.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -655,7 +655,7 @@
|
||||
"end\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"- The outer loop cannot be parallelized (like in the 1d case). \n",
|
||||
"- The outer loop cannot be parallelized (like in the 1D case). \n",
|
||||
"- The two inner loops are trivially parallel\n"
|
||||
]
|
||||
},
|
||||
@@ -666,7 +666,7 @@
|
||||
"source": [
|
||||
"### Parallelization strategies\n",
|
||||
"\n",
|
||||
"In 2d one has more flexibility in order to distribute the data over the processes. We consider these three alternatives:\n",
|
||||
"In 2D, one has more flexibility in order to distribute the data over the processes. We consider these three alternatives:\n",
|
||||
"\n",
|
||||
"- 1D block row partition (each worker handles a subset of consecutive rows and all columns)\n",
|
||||
"- 2D block partition (each worker handles a subset of consecutive rows and columns)\n",
|
||||
@@ -848,9 +848,9 @@
|
||||
"\n",
|
||||
"|Partition | Messages <br> per iteration | Communication <br>per worker | Computation <br>per worker | Ratio communication/<br>computation |\n",
|
||||
"|---|---|---|---|---|\n",
|
||||
"| 1d block | 2 | O(N) | N²/P | O(P/N) |\n",
|
||||
"| 2d block | 4 | O(N/√P) | N²/P | O(√P/N) |\n",
|
||||
"| 2d cyclic | 4 |O(N²/P) | N²/P | O(1) |"
|
||||
"| 1D block | 2 | O(N) | N²/P | O(P/N) |\n",
|
||||
"| 2D block | 4 | O(N/√P) | N²/P | O(√P/N) |\n",
|
||||
"| 2D cyclic | 4 |O(N²/P) | N²/P | O(1) |"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -862,9 +862,9 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- Both 1d and 2d block partitions are potentially scalable if $P<<N$\n",
|
||||
"- The 2d block partition has the lowest communication complexity\n",
|
||||
"- The 1d block partition requires to send less messages (It can be useful if the fixed cost of sending a message is high)\n",
|
||||
"- Both 1D and 2D block partitions are potentially scalable if $P<<N$\n",
|
||||
"- The 2D block partition has the lowest communication complexity\n",
|
||||
"- The 1D block partition requires to send less messages (It can be useful if the fixed cost of sending a message is high)\n",
|
||||
"- The best strategy for a given problem size will thus depend on the machine.\n",
|
||||
"- Cyclic partitions are impractical for this application (but they are useful in others) \n",
|
||||
"\n"
|
||||
@@ -1932,15 +1932,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
"\n",
|
||||
"### Creating a task\n",
|
||||
"\n",
|
||||
"Technically, a task in Julia is a *symmetric* [*co-routine*](https://en.wikipedia.org/wiki/Coroutine). More informally, a task is a piece of computational work that can be started (scheduled) at some point in the future, and that can be interrupted and resumed. To create a task, we first need to create a function that represents the work to be done in the task. In next cell, we generate a task that generates and sums two matrices."
|
||||
"Technically, a task in Julia is a *symmetric* [*co-routine*](https://en.wikipedia.org/wiki/Coroutine). More informally, a task is a piece of computational work that can be started (scheduled) at some point in the future, and that can be interrupted and resumed. To create a task, we first need to create a function that represents the work to be done in the task. In the next cell, we generate a task that generates and sums two matrices."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -322,7 +322,7 @@
|
||||
"source": [
|
||||
"### `yield`\n",
|
||||
"\n",
|
||||
"If tasks do not run in parallel, what is the purpose of tasks? Tasks are handy since they can be interrupted and to switch control to other tasks. This is achieved via function `yield`. When we call yield, we provide the opportunity to switch to another task. The function below is a variation of function `compute_π` in which we yield every 1000 iterations. At the call to yield we allow other tasks to take over. Without this call to yield, once we start function `compute_π` we cannot start any other tasks until this function finishes."
|
||||
"If tasks do not run in parallel, what is the purpose of tasks? Tasks are handy since they can be interrupted and to switch control to other tasks. This is achieved via function `yield`. When we call `yield`, we provide the opportunity to switch to another task. The function below is a variation of function `compute_π` in which we `yield` every 1000 iterations. At the call to `yield` we allow other tasks to take over. Without this call to `yield`, once we start function `compute_π` we cannot start any other tasks until this function finishes."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -349,7 +349,7 @@
|
||||
"id": "69fd4131",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can check this behavior experimentally with the two following cells. The next one creates and schedules a task that computes pi with the function `compute_π_yield`. Note that you can run the 2nd cell bellow while this task is running since we call to yield often inside `compute_π_yield`."
|
||||
"You can check this behavior experimentally with the two following cells. The next one creates and schedules a task that computes pi with the function `compute_π_yield`. Note that you can run the 2nd cell bellow while this task is running since we call to `yield` often inside `compute_π_yield`."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -381,7 +381,7 @@
|
||||
"source": [
|
||||
"### Example: Implementing function sleep\n",
|
||||
"\n",
|
||||
"Using yield, we can implement our own version of the sleep function as follows:"
|
||||
"Using `yield`, we can implement our own version of the sleep function as follows:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -738,7 +738,8 @@
|
||||
"\n",
|
||||
"- `put!` will wait for a `take!` if there is not space left in the channel's buffer.\n",
|
||||
"- `take!` will wait for a `put!` if there is no data to be consumed in the channel.\n",
|
||||
"- Both `put!` and `take!` will raise an error if the channel is closed."
|
||||
"- `put!` will raise an error if the channel is closed.\n",
|
||||
"- `take!` will raise an error if the channel is closed *and* empty."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1015,15 +1016,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"source": [
|
||||
"## Using Jupyter notebooks in Julia\n",
|
||||
"\n",
|
||||
"We are going to use Jupyter notebooks in this and other lectures. You provably have worked with notebooks (in Python). If not, here are the basic concepts you need to know to follow the lessons.\n",
|
||||
"We are going to use Jupyter notebooks in this and other lectures. You probably have worked with notebooks (in Python). If not, here are the basic concepts you need to know to follow the lessons.\n",
|
||||
"\n",
|
||||
"<div class=\"alert alert-block alert-info\">\n",
|
||||
"<b>Tip:</b> Did you know that Jupyter stands for Julia, Python and R?\n",
|
||||
@@ -1680,7 +1680,7 @@
|
||||
"source": [
|
||||
"### Exercise 3 (hard)\n",
|
||||
"\n",
|
||||
"Function `mandel` estimates if a given point `(x,y)` in the complex plane belongs to the [Mandelbrot set](https://en.wikipedia.org/wiki/Mandelbrot_set)."
|
||||
"Function `surprise(x,y)` takes the `x` and `y` coordinates of a point and returns a scalar value. Visualize the result of function `surprise(x,y)` for all points in a Cartesian grid of the box with range $(-1.7,0.7)$ in the horizontal direction and range $(-1.2,1.2)$ in vertical direction. Use at least `n=1000` points in each direction (1000$^2$ points in total). What do you see? Surprise!\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1690,7 +1690,11 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"function mandel(x,y,max_iters)\n",
|
||||
"function surprise(x,y)\n",
|
||||
" # You don't need to understand\n",
|
||||
" # the body of this function.\n",
|
||||
" # Treat it as a black box.\n",
|
||||
" max_iters = 100\n",
|
||||
" z = Complex(x,y)\n",
|
||||
" c = z\n",
|
||||
" threshold=2\n",
|
||||
@@ -1700,22 +1704,38 @@
|
||||
" end\n",
|
||||
" z = z^2 +c\n",
|
||||
" end\n",
|
||||
" max_iters\n",
|
||||
" return max_iters\n",
|
||||
"end"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {
|
||||
"Screenshot%20from%202025-09-05%2014-41-15.png": {
|
||||
"image/png": "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iSee0IULF7IdDwkJ0SuvvOLQVAAAAACcRIkGfiUrK0uHDh3SvHnzFBcXpxUrVvg8plu3brrnnnscmA4AAACA0zyWZVlODwE4qV27dvrqq69sPTYiIkK7du1S9erVDU8FAAAAwI34SzRgk8fj0bhx4yjQAAAAQDFGiQZsCAkJ0TvvvKOePXs6PQoAAAAAB1GigTx4PB49/PDDWrt2rZ577jmnxwEAAADgMN4TjWJv1qxZSktLy3asbNmyqlatmpo0aaIqVao4NBkAAAAAt6FEAwAAAABgEy/nBgAAAADAJko0AAAAAAA2UaIBAAAAALCJEg0AAAAAgE2UaAAAAAAAbKJEAwAAAABgEyUaAAAAAACbKNEAAAAAANhEiQYAAAAAwCZKNAAAAAAANlGiAQAAAACwiRINAAAAAIBNlGgAAAAAAGyiRAMAAAAAYBMlGgAAAAAAmyjRAAAAAADYRIkGAAAAAMAmSjQAAAAAADZRogEAAAAAsIkSDQAAAACATZRoAAAAAABsokQDAAAAAGATJRoAAAAAAJso0YCfnT9/3ukRAAAAABhCiQb85NixY2ratKnKlSunZs2a6dChQ06PBAAAAMDPPJZlWU4PAQS7n376SQ8//LB2796tEiVK6PLly4qKitK6detUo0YNp8cDAAAA4Cf8JRoopIMHDyouLk67d+9WTEyMUlNT1bp1ax09elSPPPKITp065fSIAAAAAPyEEg0UwrFjx/Twww9r//79atasmVauXKnq1atr9uzZatSokfbt26f27dvr7NmzTo8KAAAAwA8o0UABZWZmql27dkpNTVVcXJyWLVum8uXLS5LKlCmjBQsWqFatWtqwYYMaN26sGTNmKCsry+GpAQAAABQGJRoooDFjxmjbtm26++67tXDhQrVv314ej0cej0ctWrRQ5cqVtXbtWtWvX1/79u1T9+7d1bRpU50+fdrp0QEAAAAUECUaKIB//vOf+stf/iJJeuqppxQREZHj426++WZt3rxZn376qWrVqqXNmzerUaNGGj9+vC5duhTIkQEAAAD4ASUaKIAFCxbo4sWLuvHGG9WpU6c8HxsSEqKePXtq06ZNatSokfbv36+hQ4cqLi6O90oDAAAAQYYSDeTT2bNnNWHCBEnSa6+9pujoaFtfFxkZqY0bN2rBggW6++67tW3bNrVv316XL182OS4AAAAAP6JEAzZdvHhRvXv3VmRkpPbu3avY2Fj98Y9/zNcaHo9HCQkJatq0qSRp3bp1+uqrr0yMCwAAAMAASjRgw6VLl9S8eXNNnTpVYWFhiomJ0YIFCxQeHl6g9e6//36FhPz7/37jx4/XhQsX/DkuAAAAAEMo0YANU6ZM0ebNm3XXXXcpJSVFO3bsULVq1Qq8Xr9+/TR//nyVK1dOy5cvV2xsrCZOnKiMjAw/Tg0AAADA3yjRwHWcOXNGo0ePliS9/fbbuvXWW/2ybrt27bRlyxbdd999SklJ0VNPPcXFxgAAAACXo0QDefj555/Vtm1bpaamqmHDhkpISPDr+rVq1dLWrVs1f/583X333dq6das6dOigX375xa/7AAAAAPAPSjSQi23btql+/frauHGj7rzzTi1cuFAej8fv+3g8HrVv314rV65U6dKltXbtWk2cONHv+wAAAAAoPEo08BunT5/WH/7wBzVt2lQpKSlq1KiRli9frsqVKxvd95dfftHFixclSTfddJPRvQAAAAAUDCUa+A+v16tx48apdu3a+uCDDyRJL7/8statW2f7s6ALo0aNGmrUqJEk6YMPPtDRo0eN7wkAAAAgfyjRwH+sXLlSTz/9tE6dOqV27dpp165devPNNwv8MVYFMWfOHN1777367rvv1L1794DtCwAAAMAeSjTwH61atdIf/vAHLVmyRAsXLtSdd94Z8BmioqK0cuVKSdLatWvVrVu3gM8AAAAAIHeUaOBX3nvvPbVu3drRGSpUqKDOnTtLkmbNmqUKFSo4Og8AAACA/0OJBlzoiy++0GOPPSZJysjI0IkTJxyeCAAAAIBEiQZca9q0aWrYsKEuXLigKlWqaPjw4U6PBAAAABR7lGjAxT7//HPFxcXJsiydOnXK6XEAAACAYi/M6QEA5K5mzZpau3atzp8/r1KlSjk9DgAAAFDsUaKBIHDTTTc5PQIAAAAA8XJuAAAAAABso0QDAAAAAGATL+d2gNfr1c8//5zt2A033OCa97xmZWVp7969+vbbb7V3714dP35c586d04033qhy5crptttuU5MmTRQbG6vw8HCnxwUAAACAgKFEG3blyhX98MMP2rZtm7Zu3apt27Zp586dunjxYrbHPfvssxo9erRDU0q//PKL5s+frwULFmjZsmW2Ppc4MjJS/fr109ChQ3XLLbcEYEoAAAAAcBYl2oB//etf+utf/6pt27Zpx44dunDhgtMj5SozM1ODBg3S7Nmzdf78+Xx97enTp/XOO+9owoQJGjVqlAYOHCiPx2NoUgAAAABwHiXagIMHD+r99993egxbMjIy9PHHHxdqjfT0dD355JPau3dv0DxvAAAAACgISjRydPvttysuLk5NmjRRLine truncated
|
||||
}
|
||||
},
|
||||
"cell_type": "markdown",
|
||||
"id": "86ea2591",
|
||||
"id": "de548741",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"If the value of `mandel` is less than `max_iters`, the point is provably outside the Mandelbrot set. If `mandel` is equal to `max_iters`, then the point is provably inside the set. The larger `max_iters`, the better the quality of the estimate (the nicer will be your plot).\n",
|
||||
"The gid of points is shown in the next figure for `n=7` (but you should use at least `n=1000`).\n",
|
||||
"\n",
|
||||
"Plot the value of function `mandel` for each pixel in a 2D grid of the box.\n",
|
||||
"<div>\n",
|
||||
"<img src=\"attachment:Screenshot%20from%202025-09-05%2014-41-15.png\", width=\"550\">\n",
|
||||
"</div>\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "95e81488",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Hints\n",
|
||||
"\n",
|
||||
"$$(-1.7,0.7)\\times(-1.2,1.2).$$\n",
|
||||
"\n",
|
||||
"Use a grid resolution of at least 1000 points in each direction and `max_iters` at least 10. You can increase these values to get nicer plots. To plot the values use function `heatmap` from the Julia package `GLMakie`. Use `LinRange` to divide the horizontal and vertical axes into pixels. See the documentation of these functions for help. `GLMakie` is a GPU-accelerated plotting back-end for Julia. It is a large package and it can take some time to install and to generate the first plot. Be patient."
|
||||
"* Create a matrix `values` of the right size and fill it in so that `values[i,j]=surprise(x[i],y[j])` is the value for point `i` in the horizontal direction and `j` in the vertical direction (see the figure above).\n",
|
||||
"* The vectors `x` and `y` can be created with function `LinRange`.\n",
|
||||
"* Visualize the values in `values` with function `heatmap` from the Julia package `GLMakie`. `GLMakie` is a GPU-accelerated plotting back-end for Julia. It is a large package and it can take some time to install and to generate the first plot. Be patient.\n",
|
||||
"* See the documentation of these functions for help."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1741,15 +1761,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"<div class=\"alert alert-block alert-info\">\n",
|
||||
"<b>Tip:</b> We can also start new processes when launching Julia from the command line by suing the `-p` command-line argument. E.g., `$ julia -p 3 ` would launch Julia with 3 extra processes.\n",
|
||||
"<b>Tip:</b> We can also start new processes when launching Julia from the command line by using the `-p` command-line argument. E.g., `$ julia -p 3 ` would launch Julia with 3 extra processes.\n",
|
||||
"</div>\n"
|
||||
]
|
||||
},
|
||||
@@ -251,7 +251,7 @@
|
||||
"source": [
|
||||
"### Creating workers in other machines\n",
|
||||
"\n",
|
||||
"For large parallel computations, one typically needs to use different computers in parallel. Function `addprocs` also provides a low-level method to start workers in other machines. Next code example would create 3 workers in `server1` and 4 new workers in server `server2` (see figure below). Under the hood, Julia connects via ssh to the other machines and starts the new processes there. In order this to work, the local computer and the remote servers need to be properly configured (see the Julia manual for details). \n",
|
||||
"For large parallel computations, one typically needs to use different computers in parallel. Function `addprocs` also provides a low-level method to start workers in other machines. Next code example would create 3 workers in `server1` and 4 new workers in `server2` (see figure below). Under the hood, Julia connects via ssh to the other machines and starts the new processes there. In order this to work, the local computer and the remote servers need to be properly configured (see the Julia manual for details). \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -278,34 +278,6 @@
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6c09b2e5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Adding workers with ClusterManagers.jl\n",
|
||||
"\n",
|
||||
"Previous way of starting workers in other machines is very low-level. Happily, there is a Julia package called [ClusterManagers.jl](https://github.com/JuliaParallel/ClusterManagers.jl) that helps to create workers remotely in number of usual scenarios. For instance, when running the following code from the login node in a computer cluster, it will submit a job to the cluster queue allocating 128 threads. A worker will be generated for each one of these threads. If the compute node have 64 cores, 2 compute nodes will be used to create to contain the 128 workers (see below).\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"```julia\n",
|
||||
"using Distributed\n",
|
||||
"using ClusterManagers\n",
|
||||
"addprocs(SlurmManager(128), partition=\"debug\", t=\"00:5:00\")\n",
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7c470ed9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
" <div>\n",
|
||||
"<img src=\"data:image/png;base64,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 truncated
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8c8bc619",
|
||||
@@ -514,7 +486,7 @@
|
||||
"id": "10899cd4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Another usefull macro: `@fetchfrom`\n",
|
||||
"### Another useful macro: `@fetchfrom`\n",
|
||||
"\n",
|
||||
"Macro `@fetchfrom` is the blocking version of `@spawnat`. It blocks and returns the corresponding result instead of a `Future` object. "
|
||||
]
|
||||
@@ -552,7 +524,7 @@
|
||||
"source": [
|
||||
"### Explicit data movement in `remotecall` / `fetch`\n",
|
||||
"\n",
|
||||
"When usig `remotecall` we send to the remote process a function and its arguments. In this example, we send function name `+` and matrices `a` and `b` to proc 4. When fetching the result we receive a copy of the matrix from proc 4."
|
||||
"When using `remotecall` we send to the remote process a function and its arguments. In this example, we send function name `+` and matrices `a` and `b` to proc 4. When fetching the result we receive a copy of the matrix from proc 4."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1445,15 +1417,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.5",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.5"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
"```julia\n",
|
||||
"using MPI\n",
|
||||
"MPI.Init()\n",
|
||||
"# Your MPI programm here\n",
|
||||
"# Your MPI program here\n",
|
||||
"MPI.Finalize() # Optional\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
@@ -176,7 +176,7 @@
|
||||
"```julia\n",
|
||||
"using MPI\n",
|
||||
"MPI.Init(finalize_atexit=false)\n",
|
||||
"# Your MPI programm here\n",
|
||||
"# Your MPI program here\n",
|
||||
"MPI.Finalize() # Mandatory\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
@@ -186,7 +186,7 @@
|
||||
"#include <mpi.h>\n",
|
||||
"int main(int argc, char** argv) {\n",
|
||||
" MPI_Init(NULL, NULL);\n",
|
||||
" /* Your MPI Programm here */\n",
|
||||
" /* Your MPI Program here */\n",
|
||||
" MPI_Finalize();\n",
|
||||
"}\n",
|
||||
"```\n",
|
||||
@@ -612,7 +612,7 @@
|
||||
"id": "4b455f98",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"So, the full MPI program needs to be in the source file passed to Julia or the quote block. In practice, long MPI programms are written as Julia packages using several files, which are then loaded by each MPI process. For our simple example, we just need to include the definition of `foo` inside the quote block."
|
||||
"So, the full MPI program needs to be in the source file passed to Julia or the quote block. In practice, long MPI programs are written as Julia packages using several files, which are then loaded by each MPI process. For our simple example, we just need to include the definition of `foo` inside the quote block."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -920,7 +920,7 @@
|
||||
" source = MPI.ANY_SOURCE\n",
|
||||
" tag = MPI.ANY_TAG\n",
|
||||
" status = MPI.Probe(comm,MPI.Status; source, tag)\n",
|
||||
" count = MPI.Get_count(status,Int) # Get incomming message length\n",
|
||||
" count = MPI.Get_count(status,Int) # Get incoming message length\n",
|
||||
" println(\"I am about to receive $count integers.\")\n",
|
||||
" rcvbuf = zeros(Int,count) # Allocate \n",
|
||||
" MPI.Recv!(rcvbuf, comm, MPI.Status; source, tag)\n",
|
||||
@@ -973,7 +973,7 @@
|
||||
" if rank == 3\n",
|
||||
" rcvbuf = zeros(Int,5)\n",
|
||||
" MPI.Recv!(rcvbuf, comm, MPI.Status; source=2, tag=0)\n",
|
||||
" # recvbuf will have the incomming message fore sure. Recv! has returned.\n",
|
||||
" # recvbuf will have the incoming message fore sure. Recv! has returned.\n",
|
||||
" @show rcvbuf\n",
|
||||
" end\n",
|
||||
"end\n",
|
||||
@@ -1590,15 +1590,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
"## Where can we exploit parallelism?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"The matrix-matrix multiplication is an example of [embarrassingly parallel algorithm](https://en.wikipedia.org/wiki/Embarrassingly_parallel). An embarrassingly parallel (also known as trivially parallel) algorithm is an algorithm that can be split in parallel tasks with no (or very few) dependences between them. Such algorithms are typically easy to parallelize.\n",
|
||||
"The matrix-matrix multiplication is an example of [embarrassingly parallel algorithm](https://en.wikipedia.org/wiki/Embarrassingly_parallel). An embarrassingly parallel (also known as trivially parallel) algorithm is an algorithm that can be split in parallel tasks with no (or very few) dependencies between them. Such algorithms are typically easy to parallelize.\n",
|
||||
"\n",
|
||||
"Which parts of an algorithm are completely independent and thus trivially parallel? To answer this question, it is useful to inspect the for loops, which are potential sources of parallelism. If the iterations are independent of each other, then they are trivial to parallelize. An easy check to find out if the iterations are dependent or not is to change their order (for instance changing `for j in 1:n` by `for j in n:-1:1`, i.e. doing the loop in reverse). If the result changes, then the iterations are not independent.\n",
|
||||
"\n",
|
||||
@@ -314,7 +314,7 @@
|
||||
"Note that:\n",
|
||||
"\n",
|
||||
"- Loops over `i` and `j` are trivially parallel.\n",
|
||||
"- The loop over `k` is not trivially parallel. The accumulation into the reduction variable `Cij` introduces extra dependences. In addition, remember that the addition of floating point numbers is not strictly associative due to rounding errors. Thus, the result of this loop may change with the loop order when using floating point numbers. In any case, this loop can also be parallelized, but it requires a parallel *fold* or a parallel *reduction*.\n",
|
||||
"- The loop over `k` is not trivially parallel. The accumulation into the reduction variable `Cij` introduces extra dependencies. In addition, remember that the addition of floating point numbers is not strictly associative due to rounding errors. Thus, the result of this loop may change with the loop order when using floating point numbers. In any case, this loop can also be parallelized, but it requires a parallel *fold* or a parallel *reduction*.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
@@ -1138,15 +1138,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -944,15 +944,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.9.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.9"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.9.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
+3
-3
@@ -1217,15 +1217,15 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Julia 1.10.0",
|
||||
"display_name": "Julia 1.11.6",
|
||||
"language": "julia",
|
||||
"name": "julia-1.10"
|
||||
"name": "julia-1.11"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".jl",
|
||||
"mimetype": "application/julia",
|
||||
"name": "julia",
|
||||
"version": "1.10.0"
|
||||
"version": "1.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
Reference in new issue
Block a user