commit
a0b19270d7
@ -13,7 +13,7 @@ nothing
|
||||
|
||||
The [Makie.jl webpage](https://github.com/JuliaPlots/Makie.jl) says
|
||||
|
||||
> From the Jpanese word Maki-e, which is a technique to sprinkle lacquer with gold and silver powder. Data is basically the gold and silver of our age, so let's spread it out beautifully on the screen!
|
||||
> From the Japanese word Maki-e, which is a technique to sprinkle lacquer with gold and silver powder. Data is basically the gold and silver of our age, so let's spread it out beautifully on the screen!
|
||||
|
||||
`Makie` itself is a metapackage for a rich ecosystem. We show how to
|
||||
use the interface provided by `AbstractPlotting` and the `GLMakie`
|
||||
|
@ -48,7 +48,7 @@ var trace1 = {
|
||||
|
||||
The `{}` create a list, the `[]` an Array (or vector, as it does with `Julia`), the `name:` are keys. The above is simply translated via:
|
||||
|
||||
```julia
|
||||
```julia;
|
||||
Config(x = [1,2,3,4],
|
||||
y = [10, 15, 13, 17],
|
||||
mode = "markers",
|
||||
@ -58,7 +58,7 @@ Config(x = [1,2,3,4],
|
||||
|
||||
The `Config` constructor (from the `EasyConfig` package loaded with `PlotlyLight`) is an interface for a dictionary whose keys are symbols, which are produced by the named arguments passed to `Config`. By nesting `Config` statements, nested `JavaScript` structures can be built up. As well, these can be built on the fly using `.` notation, as in:
|
||||
|
||||
```julia
|
||||
```julia; hold=true
|
||||
cfg = Config()
|
||||
cfg.key1.key2.key3 = "value"
|
||||
cfg
|
||||
@ -159,7 +159,7 @@ p # to display the plot
|
||||
|
||||
The values for `a` and `b` are used to generate the ``x``- and ``y``-values. These can also be gathered from the existing plot object. Here is one way, where for each trace with an `x` key, the extrema are consulted to update a list of left and right ranges.
|
||||
|
||||
```julia
|
||||
```julia; hold=true
|
||||
xs, ys = PlotUtils.adapted_grid(x -> x^5 - x - 1, (0, 2)) # answer is (0,2)
|
||||
p = Plot([Config(x=xs, y=ys, name="Polynomial"),
|
||||
Config(x=xs, y=0 .* ys, name="x-axis", mode="lines", line=Config(width=5))]
|
||||
@ -223,7 +223,7 @@ values between ``0`` and ``1``.) A string with this content can be
|
||||
specified. Otherwise, something like the following can be used to
|
||||
avoid the type piracy:
|
||||
|
||||
```julia
|
||||
```julia;
|
||||
struct rgb
|
||||
r
|
||||
g
|
||||
@ -398,7 +398,7 @@ Plot(data, layout)
|
||||
```
|
||||
|
||||
|
||||
The following example is more complicated use of the elements previously described. It comes from an image from [Wikipedia](https://en.wikipedia.org/wiki/List_of_trigonometric_identities) for trigonometric identities. The use of ``\LaTeX`` does not seem to be supported through the `JavaScript` interface; unicode symbols are used instead. The `xanchor` and `yanchor` keys are used to position annotations away from the default. The `textangle` key is used to rotate text, as desired.
|
||||
The following example is more complicated use of the elements previously described. It comes mimics an image from [Wikipedia](https://en.wikipedia.org/wiki/List_of_trigonometric_identities) for trigonometric identities. The use of ``\LaTeX`` does not seem to be supported through the `JavaScript` interface; unicode symbols are used instead. The `xanchor` and `yanchor` keys are used to position annotations away from the default. The `textangle` key is used to rotate text, as desired.
|
||||
|
||||
```julia, hold=true
|
||||
alpha = pi/6
|
||||
@ -541,7 +541,7 @@ helix(t) = [cos(t), sin(t), t]
|
||||
helix′(t) = [-sin(t), cos(t), 1]
|
||||
ts = range(0, 4pi, length=200)
|
||||
xs, ys, zs = unzip(helix.(ts))
|
||||
helix_trace = Config(;NamedTuple(zip((:x,:y,:z), unzip(helix.(ts))))...,
|
||||
helix_trace = Config(; NamedTuple(zip((:x,:y,:z), unzip(helix.(ts))))...,
|
||||
type = "scatter3d", # <<- note the 3d
|
||||
mode = "lines",
|
||||
line=(width=2,
|
||||
|
@ -2,16 +2,28 @@
|
||||
|
||||
To run the commands in these notes, some external packages must be installed and loaded.
|
||||
|
||||
All that is needed is to install the `CalculusWithJulia` package with:
|
||||
The `Pluto` interface does this in the background, so there is nothing to do but execute the cells that call `using` or `import`.
|
||||
|
||||
----
|
||||
|
||||
For other interfaces, to use the `CalculusWithJulia` package requires first that it be installed. From the command line, this would be done with
|
||||
All that is needed is to install with:
|
||||
|
||||
```julia; eval=false
|
||||
] add CalculusWithJulia
|
||||
```
|
||||
|
||||
This only needs to be done once.
|
||||
Using the `Pkg` package, the commands would be
|
||||
|
||||
```julia; eval=false
|
||||
import Pkg
|
||||
Pkg.add("CalculusWithJulia")
|
||||
```
|
||||
|
||||
Installation only needs to be done once.
|
||||
|
||||
|
||||
However, for each new `Julia` session, the package must be *loaded* with the following command:
|
||||
However, for each new `Julia` session, the package must be *loaded*, as with the following command:
|
||||
|
||||
```julia;
|
||||
using CalculusWithJulia
|
||||
@ -29,31 +41,30 @@ That is all. The rest of this page just provides some details for the interested
|
||||
|
||||
The `Julia` language provides the building blocks for the wider `Julia` ecosystem that enhance and extend the language's applicability.
|
||||
|
||||
`Julia` is extended through "packages." Some of these, such as packages for certain math constants and some linear algebra operations, are part of all `Julia` installations and must simple by loaded to be used. Others, such as packages for finding integrals or (automatic) derivatives are provided by uses and must first be *installed* before being used.
|
||||
`Julia` is extended through "packages." Some of these, such as packages for certain math constants and some linear algebra operations, are part of all `Julia` installations and must simple by loaded to be used. Others, such as packages for finding integrals or (automatic) derivatives are provided by users and must first be *installed* before being used.
|
||||
|
||||
### Package installation
|
||||
|
||||
Package installation is straightforward, as `Julia` has a package, `Pkg`, that facilitates this. The command line and `IJulia` provide access to the function in `Pkg` through the escape command `]`. For example, to find the status of all currently installed packages, the following command can be executed:
|
||||
Package installation is straightforward, as `Julia` has a package, `Pkg`, that facilitates this.
|
||||
|
||||
Since `Julia` version 1.7, just attempting to load a package through `using PackageName` at the *command line* will either load an installed package *or* query for an uninstalled package to be installed before lading. So installation just requires confirming a prompt.
|
||||
|
||||
For more control, the command line and `IJulia` provide access to the function in `Pkg` through the escape command `]`. For example, to find the status of all currently installed packages, the following command can be executed:
|
||||
|
||||
```julia; eval=false
|
||||
] status
|
||||
```
|
||||
|
||||
External packages are *typically* installed from GitHub and if they are regisered, installation is as easy as call `add`:
|
||||
External packages are *typically* installed from GitHub and if they are regisered, installation is as easy as calling `add`:
|
||||
|
||||
```julia; eval=false
|
||||
] add QuadGK
|
||||
```
|
||||
|
||||
That command will consult `Julia`'s general regisrty for the location of the `QuadGK` package, use this location to download the necessary files, if necessary will build or install dependencies, and then make the package available for use.
|
||||
That command will consult `Julia`'s general registry for the location of the `QuadGK` package, use this location to download the necessary files, if necessary dependencies will be built and installed, and then the package available for use.
|
||||
|
||||
For these notes, when the `CalculusWithJulia` package is installed it will also install all the other packages that are needed.
|
||||
For these notes, when the `CalculusWithJulia` package is installed it will also install many of the other packages that are needed.
|
||||
|
||||
```julia; echo=false;
|
||||
note("""
|
||||
Installing the `CalculusWithJulia` package is the only package necessary to install for these notes.
|
||||
""")
|
||||
```
|
||||
|
||||
See [Pkg](https://docs.julialang.org/en/v1/stdlib/Pkg/index.html) for more details, such as how to update the set of available packages.
|
||||
|
||||
@ -80,7 +91,7 @@ quadgk(sin, 0, pi)
|
||||
|
||||
### Package details
|
||||
|
||||
When a package if *first* loaded after installation, or some other change, it will go through a *pre-compilation* process. Depending on the package size, this can take a moment to several seconds. This won't happen the second time a package is loaded.
|
||||
When a package is *first* loaded after installation, or some other change, it will go through a *pre-compilation* process. Depending on the package size, this can take a moment to several seconds. This won't happen the second time a package is loaded.
|
||||
|
||||
|
||||
However, subsequent times a package is loaded some further compilation is done, so it can still take some time for a package to load. Mostly this is not noticeable, though with the plotting package used in these notes, it is.
|
||||
@ -89,9 +100,9 @@ However, subsequent times a package is loaded some further compilation is done,
|
||||
When a package is loaded, all of its dependent packages are also loaded, but their functions are not immediately available to the user.
|
||||
|
||||
|
||||
In *typical* `Julia` usage, each needed package is loaded on demand. This is faster and also keeps the namespace (the collection of variable and function names) smaller to avoid collisions. However, for these notes, the package `CalculusWithJulia` will load all the packages needed for the entire set of notes, not just the current section. This is to make it *easier* for the *beginning* user.
|
||||
In *typical* `Julia` usage, each needed package is loaded on demand. This is faster and also keeps the namespace (the collection of variable and function names) smaller to avoid collisions. However, for these notes, the package `CalculusWithJulia` will load a few of the packages needed for the entire set of notes, not just the current section. This is to make it a bit *easier* for the *beginning* user.
|
||||
|
||||
One issue with loading several packages is the possibility that more than one will export a function with the same name, causing a collision.
|
||||
One issue with loading several packages is the possibility that more than one will export a function with the same name, causing a collision. Moreover, at times, there can be dependency conflicts between packages. A suggested workflow is to use projects and in each project use a minimal set of packages. In Pluto, this is done behind the scenes.
|
||||
|
||||
The `Julia` language is designed around have several "generic" functions each with many different methods depending on their usage. This design allows many different implementations for operations such as addition or multiplication yet the user only needs to call one function name. Packages can easily extend these generic functions by providing their own methods for their own new types of data. For example, `SymPy`, which adds symbolic math features to `Julia` (using a Python package) extends both `+` and `*` for use with symbolic objects.
|
||||
|
||||
@ -99,4 +110,4 @@ This design works great when the "generic" usage matches the needs of the packag
|
||||
|
||||
* The extension of a generic is for a type defined outside the author's package. This is known as "type piracy" and is frowned on, as it can lead to subtle errors. The `CalculusWithJulia` package practices this for one case: using `'` to indicate derivatives for `Function` objects.
|
||||
|
||||
* The generic function concept is not part of base `Julia`. An example might be the `solve` function. This name has a well-defined mathematical usage (e.g., "solve for $x$."), but the generic concept is not part of base `Julia`. It is part of `SymPy` and it is part of `DifferentialEquations`. That is, both package export this function name. For the user, if *both* packages are loaded, then they user **must** *qualify* which package's `solve` function they mean, as in `SymPy.solve` or `DifferentialEquations.solve`. (`DifferentialEquations` is not part of `CalculusWithJulia` and is just briefly used in these notes, though is an incredible set of packages and a testament to the strengths and power of `Julia`.)
|
||||
* The generic function concept is not part of base `Julia`. An example might be the `solve` function. This name has a well-defined mathematical usage (e.g., "solve for $x$."), but the generic concept is not part of base `Julia`. As it is used by `SymPy` and `DifferentialEquations`, among others, the ecosystem has a stub package `CommonSolve` allowing the sharing of this "verb."
|
||||
|
@ -4,7 +4,6 @@
|
||||
```julia; echo=false; results="hidden"
|
||||
using CalculusWithJulia
|
||||
using CalculusWithJulia.WeaveSupport
|
||||
using Plots
|
||||
nothing
|
||||
```
|
||||
|
||||
@ -14,18 +13,25 @@ As it is open source, indeed with a liberal MIT license, it can be
|
||||
installed for free on many types of computers (though not phones or
|
||||
tablets).
|
||||
|
||||
## Running Julia through the web
|
||||
|
||||
There are a few services for running `Julia` through the
|
||||
web. Mentioned here is [Binder](https://mybinder.org), which provides
|
||||
a web-based interface to `Julia` built around `Jupyter`. `Jupyter` is
|
||||
a wildly succesful platform for interacting with different open-source
|
||||
software programs.
|
||||
|
||||
[lauch binder](https://mybinder.org/v2/gh/CalculusWithJulia/CwJScratchPad.git/master)
|
||||
|
||||
### Installing Julia locally
|
||||
|
||||
There is the service [Binder](https://mybinder.org), which
|
||||
provides a web-based interface to `Julia` built around `Jupyter`, a
|
||||
wildly succesful platform for interacting with different open-source
|
||||
software programs. Clicking the launch button above will open a web
|
||||
page which provides a blank notebook, save for a package used by these
|
||||
notes. However, `Binder` is nowhere near as reliable as a local installation.
|
||||
Clicking the launch link above will open a web page which provides a
|
||||
blank notebook, save for a package used by these notes. However,
|
||||
`Binder` is nowhere near as reliable as a local installation.
|
||||
|
||||
Installing `Julia` locally is not more difficult than installing other softward.
|
||||
|
||||
## Installing Julia locally
|
||||
|
||||
Installing `Julia` locally is not more difficult than installing other software.
|
||||
|
||||
Binaries of `Julia` are provided at
|
||||
[julialang.org](http://julialang.org/downloads/). Julia has an
|
||||
@ -39,7 +45,10 @@ For Windows users, there is a `juliaup` program for managing the installation of
|
||||
The base `Julia` provides a *command-line interface*, or REPL
|
||||
(read-evaluate-parse).
|
||||
|
||||
### Basic interactive usage
|
||||
|
||||
|
||||
|
||||
## Basic interactive usage
|
||||
|
||||
Once installed, `Julia` can be started by clicking on an icon or
|
||||
typing `julia` at the command line. Either will open a *command line
|
||||
@ -75,103 +84,32 @@ coloring. For example:
|
||||
2 + 2
|
||||
```
|
||||
|
||||
Other interfaces to `Julia` are described briefly in [Julia interfaces](./julia_interfaces.html). The notebook interface provided through `IJulia` most closely matches the style of the notes.
|
||||
While many prefer a command line for interacting with `Julia`, when learning a notebook interfaces is suggested. (An IDE like [Julia for Visual Studio Code](https://www.julia-vscode.org/) might be preferred for experienced programmers). In [Julia interfaces](./julia_interfaces.html), we describe two different notebook interfaces that are available through add-on packages. (These notes use `Pluto`, one of the two.)
|
||||
|
||||
|
||||
|
||||
## Add-on packages
|
||||
|
||||
`Julia` has well over a 1000 external, add-on packages that enhance the
|
||||
offerings of base `Julia`. We refer to one, `CalculusWithJulia`, that is designed to accompany these notes. This package installs several other packages that provide the needed functionality. The package (and its dependencies) can be installed through:
|
||||
offerings of base `Julia`. We refer to one, `CalculusWithJulia`, that is designed to accompany these notes. [Installation notes](./calculus_with_julia.html) are available.
|
||||
|
||||
|
||||
```julia; eval=false
|
||||
using Pkg
|
||||
Pkg.add("CalculusWithJulia")
|
||||
```
|
||||
|
||||
(Or the one liner `] add CalculusWithJulia`. Some additional details on packages is provided [here](./calculus_with_julia.html).)
|
||||
In `Julia` graphics are provided only by add-on packages -- there is no built-in
|
||||
graphing. This is the case under `Pluto` or `Jupyter` or the command line.
|
||||
|
||||
Installation only needs to be done once, but to use a package it must be loaded into each new session. This can be done with this command:
|
||||
|
||||
```julia;
|
||||
using CalculusWithJulia
|
||||
```
|
||||
|
||||
|
||||
## The basics of working with Pluto
|
||||
|
||||
The `Pluto` notebook interface is a Julia-specific interface that is started by:
|
||||
|
||||
```julia; eval=false
|
||||
using Pluto
|
||||
Pluto.run()
|
||||
```
|
||||
|
||||
These commands will cause a tab in a web browser to open to `Pluto`'s landing page. From here a new or existing notebook can be opened. Notebooks can even be opened from urls or from Pluto-generated HTML pages, such as some of the sections of these notes.
|
||||
|
||||
Pluto cells are reactive, so modifications of a variable in the top-level scope will propagate to all references of that variable. This is very useful for explorations, but does require unique variable names in the top-level scope. (Names can be reused in functions and `let` blocks.)
|
||||
|
||||
A Pluto cell holds a single command, which may be a block holding multiple statements. Cells are executed, typically, by typing "shift-enter". The output of the cell appears *above* the cell.
|
||||
|
||||
|
||||
## The basics of working with IJulia
|
||||
|
||||
The **very** basics of the Jupyter notebook interface provided by `IJulia` are covered here.
|
||||
|
||||
An `IJulia` notebook is made up of cells. Within a cell a collection of commands may be typed (one or more).
|
||||
|
||||
When a cell is executed (by the triangle icon or under the Cell menu) the contents of the cell are evaluated by the `Julia` kernel and any output is displayed below the cell. Typically this is just the output of the last command.
|
||||
|
||||
```julia;
|
||||
2 + 2
|
||||
3 + 3
|
||||
```
|
||||
|
||||
|
||||
If the last commands are separated by commas, then a "tuple" will be formed and each output will be displayed, separated by commas.
|
||||
|
||||
```julia;
|
||||
2 + 2, 3 + 3
|
||||
```
|
||||
|
||||
Comments can be made in a cell. Anything after a `#` will be ignored.
|
||||
|
||||
```julia;
|
||||
2 + 2 # this is a comment, you can ignore me...
|
||||
```
|
||||
|
||||
Graphics are provided by external packages. There is no built-in
|
||||
graphing. We use the `Plots` package and its default backend. The
|
||||
In these notes, we use the `Plots` package and its default backend. The
|
||||
`Plots` package provides a common interface to several different
|
||||
backends, so this choice is easily changed. The `pyplot` backend is used in these notes, though for interactive use both the `GR` and `Plotly` backends have advantages.
|
||||
backends; this choice is easily changed. The `gr` backend is used in these notes, though for interactive use the `Plotly` backend has advantages; for more complicated graphics, `pyplot` has some advantages; for publication `PGFPlotsX` has advantages.
|
||||
|
||||
The package, if installed, is loaded as any other package:
|
||||
|
||||
```julia;
|
||||
using CalculusWithJulia
|
||||
using Plots
|
||||
```
|
||||
|
||||
```julia; echo=false
|
||||
pyplot()
|
||||
```
|
||||
|
||||
With that in hand, to make a graph of a function over a range, we follow this pattern:
|
||||
|
||||
```julia;
|
||||
plot(sin, 0, 2pi)
|
||||
```
|
||||
|
||||
A few things:
|
||||
|
||||
* Cells are numbered in the order they were evaluated.
|
||||
|
||||
* This order need not be from top to bottom of the notebook.
|
||||
|
||||
* The evaluation of a cell happens within the state of the workspace,
|
||||
which depends on what was evaluated earlier.
|
||||
|
||||
* The workspace can be cleared by the "Restart" menu item under
|
||||
"Kernel". After restarting the "Run All" menu item under "Cell" can
|
||||
be used to re-run all the commands in the notebook - from top to bottom. "Run all" will also
|
||||
reload any packages.
|
||||
|
@ -8,7 +8,7 @@ nothing
|
||||
```
|
||||
|
||||
|
||||
`Julia` can be used in many different manners. This describes a few.
|
||||
`Julia` can be used in many different manners. This page describes a few.
|
||||
|
||||
|
||||
## The `REPL`
|
||||
@ -38,6 +38,14 @@ The REPL has many features for editing, for interacting with the package manager
|
||||
|
||||
The `Pluto` package provides a notebook interface for interacting with `Julia`, which has a few idiosyncrasies, as compared to other interfaces.
|
||||
|
||||
Pluto is started from the REPL terminal with these two commands:
|
||||
|
||||
```julia; eval=false
|
||||
using Pluto
|
||||
Pluto.run()
|
||||
```
|
||||
|
||||
|
||||
Primarily, the variables in the notebook are **reactive**, meaning if a variable's value is modified, all references to that variables are also modified. This reactive nature makes it very easy to see the results of slight modifications and when coupled with HTML controls, allows easy user interfaces to be developed.
|
||||
|
||||
As a result, a variable name may only be used once in the top-level scope. (Names can be reused inside functions, which create their own scope and in "`let`" blocks, a trick used within these notes.) In the notes, subscripting and unicode variants are used for symbols which are typically repurposed (e.g., `x` or `f`).
|
||||
@ -46,18 +54,24 @@ Pluto cells may only contain one command, the result of which is displayed *abov
|
||||
|
||||
Pluto has a built-in package management system that manages the installation of packages on demand.
|
||||
|
||||
The sections presented as `Pluto` notebooks can be easily run locally using `Pluto`.
|
||||
`Pluto` notebooks can be easily run locally using `Pluto`.
|
||||
|
||||
`Pluto` notebooks are just `.jl` scripts, so can easily be shared.
|
||||
|
||||
## `IJulia`
|
||||
|
||||
"Project [Jupyter](https://jupyter.org/) exists to develop open-source software, open-standards, and services for interactive computing across dozens of programming languages." The `IJulia` package allows `Julia` to be one of these programming languages. This package must be installed prior to use.
|
||||
|
||||
The Jupyter Project provides two web-based interfaces to `Julia`: the Jupyter notebook and the newer JupyterLab. The [juliabox](https://www.juliabox.com/) project and the [binder](https://mybinder.org/) project use Juptyer notebooks for their primary interface to `Julia`.
|
||||
The Jupyter Project provides two web-based interfaces to `Julia`: the Jupyter notebook and the newer JupyterLab. The the [binder](https://mybinder.org/) project use Juptyer notebooks for their primary interface to `Julia`. To use a binder notebook, follow this link:
|
||||
|
||||
If not installed, these interfaces are available once `IJulia` is installed. The following command should do this:
|
||||
[lauch binder](https://mybinder.org/v2/gh/CalculusWithJulia/CwJScratchPad.git/master)
|
||||
|
||||
|
||||
To run locally, these interfaces are available once `IJulia` is installed. Since version 1.7, the following commands should do this:
|
||||
|
||||
```julia; eval=false;
|
||||
] add IJulia
|
||||
using IJulia
|
||||
notebook()
|
||||
```
|
||||
|
||||
Should that not work, then this should as well:
|
||||
@ -73,14 +87,6 @@ Pkg.add("IJulia")
|
||||
|
||||
The notebook interface has "cells" where one or more commands can be entered.
|
||||
|
||||
```julia; echo=false;
|
||||
#ImageFile("figures/julia-jupyter.png")
|
||||
nothing
|
||||
```
|
||||
|
||||
|
||||
The notes have blocks of commands, as though they are entered in a notebook.
|
||||
|
||||
|
||||
In `IJulia`, a block of commands is sent to the kernel (the `Julia` interpreter) by typing "shift+return" or clicking on a "run" button. The output is printed below a cell, including graphics.
|
||||
|
||||
@ -100,29 +106,8 @@ If the kernal appears unresponsive, it can be restarted through a menu item of
|
||||
|
||||
Notebooks can be saved (as `*.ipynb` files) for sharing or for reuse. Notebooks can be printed at HTML pages, and if the proper underlying software is available, as formatted pages.
|
||||
|
||||
----
|
||||
JupyterLab, a variant, has more features, commonly associated with an integrated development environment (IDE).
|
||||
|
||||
JupyterLab has more features, commonly associated with an integrated development environment (IDE).
|
||||
## VSCode
|
||||
|
||||
```julia; echo=false
|
||||
#ImageFile("figures/julia_jupyterlab.png")
|
||||
nothing
|
||||
```
|
||||
|
||||
The figure shows a notebook and a menubar in the side menu. In addition to notebooks, JupyterLab offers the change to edit source files, for example, for project development.
|
||||
|
||||
----
|
||||
|
||||
For an integrated development environment, where many features for project development are included, there are two powerful ones being developed for `Julia` that leverage various free-to-use projects.
|
||||
|
||||
|
||||
|
||||
|
||||
### Juno
|
||||
|
||||
[Juno](https://junolab.org/) is a powerful, free environment for the Julia language. Juno is based on the cross-platform, javascript-based [Atom](https://atom.io/) editor and provides interfaces for the repl, graphics, help pages, debugging, project management, etc. Atom was developed by GitHub, since acquired by Microsoft.
|
||||
|
||||
|
||||
### VSCode
|
||||
|
||||
The [VS Code](https://github.com/julia-vscode/julia-vscode) extension provides support for the julia programming language for [VS Code](https://code.visualstudio.com/). VS Code is an open-sourced code editor supported by Microsoft. Similar to `Juno`, VS Code provides a cross-platform interface to `Julia` geared towards programming within the language.
|
||||
[Julia for Visual Studio Code](https://www.julia-vscode.org/) provides support for the julia programming language for [VS Code](https://code.visualstudio.com/). VS Code is an open-sourced code editor supported by Microsoft. VS Code provides a cross-platform interface to `Julia` geared towards programming within the language.
|
||||
|
@ -1,14 +1,19 @@
|
||||
# Quick introduction to calculus with Julia
|
||||
# Quick introduction to Calculus with Julia
|
||||
|
||||
Julia can be downloaded and used like other programming languages.
|
||||
|
||||
[launch binder](https://mybinder.org/v2/gh/CalculusWithJulia/CwJScratchPad.git/master)
|
||||
|
||||
Julia can be used through the internet for free using the [mybinder.org](https://mybinder.org) service.
|
||||
To do so, click on the `CalcululsWithJulia.ipynb` file after launching Binder by clicking on the badge.
|
||||
The `Julia` programming language with a design that makes it well suited as a supplement for the learning of calculus, as this collection of notes is intended to illustrate.
|
||||
|
||||
|
||||
These notes are transitioning from HTML pages to Pluto HTML pages, meaning they can be downloaded and run as notebooks within Pluto. Pluto will handle the package management for add-on packages automatically, though `Pluto` itself must be installed. In a terminal session, the following commands will install `Pluto`:
|
||||
As `Julia` is open source, it can be downloaded and used like many other programming languages.
|
||||
|
||||
|
||||
|
||||
Julia can be used through the internet for free using the [mybinder.org](https://mybinder.org) service. This link: [launch binder](https://mybinder.org/v2/gh/CalculusWithJulia/CwJScratchPad.git/master) will take you to website that allows this.
|
||||
Just click on the `CalcululsWithJulia.ipynb` file after launching Binder by clicking on the badge. Binder provides the Jupyter interface.
|
||||
|
||||
|
||||
These notes are written as Pluto HTML pages. Pluto is a notebook like alternative to Jupyter which is designed for interactive Julia usage using a *reactive model*. The HTML pages
|
||||
an be downloaded and run as notebooks within Pluto. (They can also be run through binder, but that will be a disappointing experience due to limitations imposed by binder.)
|
||||
Pluto will automatically handle the package management for add-on packages, though `Pluto` itself must be installed. In a terminal session, the following commands will install `Pluto`:
|
||||
|
||||
```julia; eval=false
|
||||
import Pkg
|
||||
@ -28,12 +33,6 @@ Pluto.run()
|
||||
|
||||
----
|
||||
|
||||
```julia; echo=false; results="hidden"
|
||||
using CalculusWithJulia
|
||||
using CalculusWithJulia.WeaveSupport
|
||||
using Plots
|
||||
nothing
|
||||
```
|
||||
|
||||
|
||||
|
||||
@ -62,8 +61,6 @@ Packages need only be installed once, but they must be loaded into *each* sessio
|
||||
|
||||
```julia;
|
||||
using CalculusWithJulia
|
||||
using Plots
|
||||
using SymPy
|
||||
```
|
||||
|
||||
Packages can also be loaded through `import PackageName`. Importing does not add the exported objects of a function into the namespace, so is used when there are possible name collisions.
|
||||
@ -82,10 +79,14 @@ Functions can be defined four basic ways:
|
||||
|
||||
* one statement functions follow traditional mathematics notation:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x) = exp(x) * 2x
|
||||
```
|
||||
|
||||
|
||||
!!! note
|
||||
We see in this notebook the use of `let` blocks, which is not typical with `Pluto`. As `Pluto` is reactive -- meaning changes in a variable propagate automatically to variables which reference the changed one -- a variable can only be used *once* per notebook at the top level. The `let` block, like a function body, introduces a separate scope for the binding so `Pluto` doesn't incorporate the binding in its reactive model. This is necessary as we have more than one function named `f`. This is unlike `begin` blocks, which are quite typical in `Pluto`. The `begin` blocks allow one or more commands to occur in a cell, as the design of `Pluto` is one object per cell.
|
||||
|
||||
* multi-statement functions are defined with the `function` keyword. The `end` statement ends the definition. The last evaluated command is returned. There is no need for explicit `return` statement, though it can be useful for control flow.
|
||||
|
||||
```julia;
|
||||
@ -119,7 +120,7 @@ For mathematical functions $f: R^n \rightarrow R^m$ when $n$ or $m$ is bigger th
|
||||
|
||||
* When $n =1$ and $m > 1$ we use a "vector" for the return value
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
r(t) = [sin(t), cos(t), t]
|
||||
```
|
||||
|
||||
@ -127,8 +128,8 @@ r(t) = [sin(t), cos(t), t]
|
||||
|
||||
* When $n > 1$ and $m=1$ we use multiple arguments or pass the arguments in a container. This pattern is common, as it allows both calling styles.
|
||||
|
||||
```julia;
|
||||
f(x,y,z) = x*y + y*z + z*x
|
||||
```julia; hold=true
|
||||
f(x, y, z) = x*y + y*z + z*x
|
||||
f(v) = f(v...)
|
||||
```
|
||||
|
||||
@ -136,14 +137,14 @@ Some functions need to pass in a container of values, for this the last definiti
|
||||
|
||||
Alternatively, indexing can be used directly, as in:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x) = x[1]*x[2] + x[2]*x[3] + x[3]*x[1]
|
||||
```
|
||||
|
||||
* For vector fields ($n,m > 1$) a combination is used:
|
||||
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y,z) = [-y, x, z]
|
||||
F(v) = F(v...)
|
||||
```
|
||||
@ -152,7 +153,7 @@ F(v) = F(v...)
|
||||
|
||||
Functions are called using parentheses to group the arguments.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(t) = sin(t)*sqrt(t)
|
||||
sin(1), sqrt(1), f(1)
|
||||
```
|
||||
@ -175,7 +176,7 @@ Calling `Area(5)` will call `Area(5,5)` which will return `5*5`.
|
||||
|
||||
Similarly, the definition for a vector field:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y,z) = [-y, x, z]
|
||||
F(v) = F(v...)
|
||||
```
|
||||
@ -202,15 +203,19 @@ The main (but not sole) use of keyword arguments will be with plotting, where va
|
||||
|
||||
The add-on `SymPy` package allows for symbolic expressions to be used. Symbolic values are defined with `@syms`, as below.
|
||||
|
||||
```julia;
|
||||
|
||||
```julia
|
||||
using SymPy
|
||||
```
|
||||
|
||||
```julia;
|
||||
@syms x y z
|
||||
x^2 + y^3 + z
|
||||
```
|
||||
|
||||
Assumptions on the variables can be useful, particularly with simplification, as in
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x::real y::integer z::positive
|
||||
```
|
||||
|
||||
@ -227,7 +232,6 @@ x - x + 1 # 1 is now symbolic
|
||||
```
|
||||
|
||||
The number `PI` is a symbolic `pi`.
|
||||
a
|
||||
|
||||
```julia;
|
||||
sin(PI), sin(pi)
|
||||
@ -252,7 +256,7 @@ sympy.harmonic(10)
|
||||
|
||||
Some Sympy methods belong to the object and a called via the pattern `object.method(...)`. This too is the case using SymPy with `Julia`. For example:
|
||||
|
||||
```
|
||||
```julia; hold=true
|
||||
A = [x 1; x 2]
|
||||
A.det() # determinant of symbolic matrix A
|
||||
```
|
||||
@ -313,7 +317,7 @@ Vectors and matrices are arrays. As hinted above, arrays have mathematical opera
|
||||
|
||||
Destructuring is an alternative to indexing to get at the entries in certain containers:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
a,b,c = x2
|
||||
```
|
||||
|
||||
@ -346,13 +350,12 @@ The `for` keyword is useful for iteration, Here is a traditional for loop, as `i
|
||||
|
||||
```julia;
|
||||
for i in [1,2,3]
|
||||
print(i)
|
||||
println(i)
|
||||
end
|
||||
```
|
||||
|
||||
```julia; echo=false
|
||||
CalculusWithJulia.WeaveSupport.note("""Technical aside: For assignment within a for loop at the global level, a `global` declaration may be needed to ensure proper scoping.""")
|
||||
```
|
||||
!!! note
|
||||
Technical aside: For assignment within a for loop at the global level, a `global` declaration may be needed to ensure proper scoping.
|
||||
|
||||
List comprehensions are similar, but are useful as they perform the iteration and collect the values:
|
||||
|
||||
@ -379,12 +382,13 @@ sin.(xs) # sin(1), sin(2), sin(3)
|
||||
|
||||
This example pairs off the value in `bases` and `xs`:
|
||||
|
||||
```juila
|
||||
```julia
|
||||
bases = [5,5,10]
|
||||
log.(bases, xs) # log(5, 1), log(5,2), log(10, 3)
|
||||
```
|
||||
|
||||
This example broadcasts the scalar value for the base with `xs`:
|
||||
|
||||
```julia
|
||||
log.(5, xs)
|
||||
```
|
||||
@ -393,14 +397,14 @@ Row and column vectors can fill in:
|
||||
|
||||
```julia;
|
||||
ys = [4 5] # a row vector
|
||||
f(x,y) = (x,y)
|
||||
f.(xs, ys) # broadcasting a column and row vector makes a matrix, then applies f.
|
||||
h(x,y) = (x,y)
|
||||
h.(xs, ys) # broadcasting a column and row vector makes a matrix, then applies f.
|
||||
```
|
||||
|
||||
This should be contrasted to the case when both `xs` and `ys` are (column) vectors, as then they pair off:
|
||||
This should be contrasted to the case when both `xs` and `ys` are (column) vectors, as then they pair off (and here cause a dimension mismatch as they have different lengths):
|
||||
|
||||
```
|
||||
f.(xs, [4,5])
|
||||
```julia;
|
||||
h.(xs, [4,5])
|
||||
```
|
||||
|
||||
* The `map` function is similar, it applies a function to each element:
|
||||
@ -409,29 +413,24 @@ f.(xs, [4,5])
|
||||
map(sin, [1,2,3])
|
||||
```
|
||||
|
||||
```julia; echo=false
|
||||
CalculusWithJulia.WeaveSupport.note("""Many different computer languages implement `map`, broadcasting is less common. `Julia`'s use of the dot syntax to indicate broadcasting is reminiscent of MATLAB, but is quite different.""")
|
||||
```
|
||||
!!! note
|
||||
Many different computer languages implement `map`, broadcasting is less common. `Julia`'s use of the dot syntax to indicate broadcasting is reminiscent of MATLAB, but is quite different.
|
||||
|
||||
## Plots
|
||||
|
||||
|
||||
The following commands use the `Plots` package. The `Plots` package expects a choice of backend. We will use both `plotly` and `gr` (and occasionally `pyplot()`).
|
||||
The following commands use the `Plots` package. The `Plots` package expects a choice of backend. We will use `gr` unless, but other can be substituted by calling an appropriate command, suchas `pyplot()` or `plotly()`.
|
||||
|
||||
```julia;
|
||||
using Plots
|
||||
pyplot() # select pyplot. Use `gr()` for GR; `plotly()` for Plotly
|
||||
```
|
||||
|
||||
```julia; echo=false;
|
||||
CalculusWithJulia.WeaveSupport.note("""
|
||||
The `plotly` backend and `gr` backends are available by default. The `plotly` backend is has some interactivity, `gr` is for static plots. The `pyplot` package is used for certain surface plots, when `gr` can not be used.
|
||||
""")
|
||||
```
|
||||
!!! note
|
||||
The `plotly` backend and `gr` backends are available by default. The `plotly` backend is has some interactivity, `gr` is for static plots. The `pyplot` package is used for certain surface plots, when `gr` can not be used.
|
||||
|
||||
|
||||
|
||||
> Plotting a univariate function $f:R \rightarrow R$
|
||||
### Plotting a univariate function $f:R \rightarrow R$
|
||||
|
||||
* using `plot(f, a, b)`
|
||||
|
||||
@ -441,7 +440,7 @@ plot(sin, 0, 2pi)
|
||||
|
||||
Or
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x) = exp(-x/2pi)*sin(x)
|
||||
plot(f, 0, 2pi)
|
||||
```
|
||||
@ -452,10 +451,9 @@ Or with an anonymous function
|
||||
plot(x -> sin(x) + sin(2x), 0, 2pi)
|
||||
```
|
||||
|
||||
```julia;echo=false
|
||||
CalculusWithJulia.WeaveSupport.note("""The time to first plot can be lengthy! This can be removed by creating a custom `Julia` image, but that is not introductory level stuff. As well, standalone plotting packages offer quicker first plots, but the simplicity of `Plots` is preferred. Subsequent plots are not so time consuming, as the initial time is spent compiling functions so their re-use is speedy.
|
||||
""")
|
||||
```
|
||||
!!! note
|
||||
The time to first plot can be lengthy! This can be removed by creating a custom `Julia` image, but that is not introductory level stuff. As well, standalone plotting packages offer quicker first plots, but the simplicity of `Plots` is preferred. Subsequent plots are not so time consuming, as the initial time is spent compiling functions so their re-use is speedy.
|
||||
|
||||
|
||||
|
||||
Arguments of interest include
|
||||
@ -474,7 +472,7 @@ Arguments of interest include
|
||||
|
||||
The lower level interface to `plot` involves directly creating x and y values to plot:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
xs = range(0, 2pi, length=100)
|
||||
ys = sin.(xs)
|
||||
plot(xs, ys, color=:red)
|
||||
@ -485,7 +483,7 @@ plot(xs, ys, color=:red)
|
||||
|
||||
A symbolic expression of single variable can be plotted as a function is:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x
|
||||
plot(exp(-x/2pi)*sin(x), 0, 2pi)
|
||||
```
|
||||
@ -494,7 +492,7 @@ plot(exp(-x/2pi)*sin(x), 0, 2pi)
|
||||
|
||||
The `!` Julia convention to modify an object is used by the `plot` command, so `plot!` will add to the existing plot:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
plot(sin, 0, 2pi, color=:red)
|
||||
plot!(cos, 0, 2pi, color=:blue)
|
||||
plot!(zero, color=:green) # no a, b then inherited from graph.
|
||||
@ -502,13 +500,13 @@ plot!(zero, color=:green) # no a, b then inherited from graph.
|
||||
|
||||
The `zero` function is just 0 (more generally useful when the type of a number is important, but used here to emphasize the $x$ axis).
|
||||
|
||||
> Plotting a parameterized (space) curve function $f:R \rightarrow R^n$, $n = 2$ or $3$
|
||||
### Plotting a parameterized (space) curve function $f:R \rightarrow R^n$, $n = 2$ or $3$
|
||||
|
||||
* Using `plot(xs, ys)`
|
||||
|
||||
Let $f(t) = e^{t/2\pi} \langle \cos(t), \sin(t)\rangle$ be a parameterized function. Then the $t$ values can be generated as follows:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
ts = range(0, 2pi, length = 100)
|
||||
xs = [exp(t/2pi) * cos(t) for t in ts]
|
||||
ys = [exp(t/2pi) * sin(t) for t in ts]
|
||||
@ -517,7 +515,7 @@ plot(xs, ys)
|
||||
|
||||
* using `plot(f1, f2, a, b)`. If the two functions describing the components are available, then
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f1(t) = exp(t/2pi) * cos(t)
|
||||
f2(t) = exp(t/2pi) * sin(t)
|
||||
plot(f1, f2, 0, 2pi)
|
||||
@ -532,14 +530,14 @@ plot_parametric(0..2pi, r)
|
||||
|
||||
The low-level approach doesn't quite work as easily as desired:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
ts = range(0, 2pi, length = 4)
|
||||
vs = r.(ts)
|
||||
```
|
||||
|
||||
As seen, the values are a vector of vectors. To plot a reshaping needs to be done:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
ts = range(0, 2pi, length = 100)
|
||||
vs = r.(ts)
|
||||
xs = [vs[i][1] for i in eachindex(vs)]
|
||||
@ -550,7 +548,8 @@ plot(xs, ys)
|
||||
This approach is faciliated by the `unzip` function in `CalculusWithJulia` (and used internally by `plot_parametric`):
|
||||
|
||||
```julia;
|
||||
plot(unzip(vs)...)
|
||||
ts = range(0, 2pi, length = 100)
|
||||
plot(unzip(r.(ts))...)
|
||||
```
|
||||
|
||||
|
||||
@ -559,13 +558,13 @@ plot(unzip(vs)...)
|
||||
|
||||
An arrow in 2D can be plotted with the `quiver` command. We show the `arrow(p, v)` (or `arrow!(p,v)` function) from the `CalculusWithJulia` package, which has an easier syntax (`arrow!(p, v)`, where `p` is a point indicating the placement of the tail, and `v` the vector to represent):
|
||||
|
||||
```julia;
|
||||
```julia;hold=true
|
||||
plot_parametric(0..2pi, r)
|
||||
t0 = pi/8
|
||||
arrow!(r(t0), r'(t0))
|
||||
```
|
||||
|
||||
> Plotting a scalar function $f:R^2 \rightarrow R$
|
||||
### Plotting a scalar function $f:R^2 \rightarrow R$
|
||||
|
||||
The `surface` and `contour` functions are available to visualize a scalar function of $2$ variables:
|
||||
|
||||
@ -573,7 +572,7 @@ The `surface` and `contour` functions are available to visualize a scalar functi
|
||||
|
||||
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x, y) = 2 - x^2 + y^2
|
||||
xs = ys = range(-2,2, length=25)
|
||||
surface(xs, ys, f)
|
||||
@ -581,7 +580,9 @@ surface(xs, ys, f)
|
||||
|
||||
The function generates the $z$ values, this can be done by the user and then passed to the `surface(xs, ys, zs)` format:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x, y) = 2 - x^2 + y^2
|
||||
xs = ys = range(-2,2, length=25)
|
||||
surface(xs, ys, f.(xs, ys'))
|
||||
```
|
||||
|
||||
@ -593,31 +594,35 @@ surface(xs, ys, f.(xs, ys'))
|
||||
|
||||
The `contour` function is like the `surface` function.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
xs = ys = range(-2,2, length=25)
|
||||
f(x, y) = 2 - x^2 + y^2
|
||||
contour(xs, ys, f)
|
||||
```
|
||||
|
||||
```julia;
|
||||
The values can be computed easily enough, being careful where the transpose is needed:
|
||||
|
||||
```julia; hold=true
|
||||
xs = ys = range(-2,2, length=25)
|
||||
f(x, y) = 2 - x^2 + y^2
|
||||
contour(xs, ys, f.(xs, ys'))
|
||||
```
|
||||
|
||||
|
||||
* An implicit equation. The constraint $f(x,y)=c$ generates an
|
||||
implicit equation. While `contour` can be used for this type of
|
||||
plot - by adjusting the requested contours - the `ImplicitEquations`
|
||||
package can as well, and, perhaps. is easier.`ImplicitEquations`
|
||||
plots predicates formed by `Eq`, `Le`, `Lt`, `Ge`, and `Gt` (or some
|
||||
unicode counterparts). For example to plot when $f(x,y) = \sin(xy) -
|
||||
\cos(xy) \leq 0$ we have:
|
||||
plot - by adjusting the requested contours - the `ImplicitPlots`
|
||||
package does this to make a plot of the equations ``f(x,y) = 0``"
|
||||
|
||||
```julia;
|
||||
using ImplicitEquations
|
||||
|
||||
```julia; hold=true
|
||||
using ImplicitPlots
|
||||
f(x,y) = sin(x*y) - cos(x*y)
|
||||
plot(Le(f, 0)) # or plot(f ≦ 0) using \leqq[tab] to create that symbol
|
||||
implicit_plot(f)
|
||||
```
|
||||
|
||||
|
||||
> Plotting a parameterized surface $f:R^2 \rightarrow R^3$
|
||||
### Plotting a parameterized surface $f:R^2 \rightarrow R^3$
|
||||
|
||||
|
||||
|
||||
@ -625,7 +630,7 @@ The `pyplot` (and `plotly`) backends allow plotting of parameterized surfaces.
|
||||
|
||||
The low-level `surface(xs,ys,zs)` is used, and can be specified directly as follows:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
X(theta, phi) = sin(phi)*cos(theta)
|
||||
Y(theta, phi) = sin(phi)*sin(theta)
|
||||
Z(theta, phi) = cos(phi)
|
||||
@ -638,10 +643,11 @@ surface(X.(thetas, phis'), Y.(thetas, phis'), Z.(thetas, phis'))
|
||||
|
||||
|
||||
|
||||
> Plotting a vector field $F:R^2 \rightarrow R^2$. The `CalculusWithJulia` package provides `vectorfieldplot`, used as:
|
||||
### Plotting a vector field $F:R^2 \rightarrow R^2$.
|
||||
|
||||
```julia;
|
||||
gr() # better arrows than plotly()
|
||||
The `CalculusWithJulia` package provides `vectorfieldplot`, used as:
|
||||
|
||||
```julia; hold=true
|
||||
F(x,y) = [-y, x]
|
||||
vectorfieldplot(F, xlim=(-2, 2), ylim=(-2,2), nx=10, ny=10)
|
||||
```
|
||||
@ -653,7 +659,7 @@ There is also `vectorfieldplot3d`.
|
||||
|
||||
Limits can be investigated numerically by forming tables, eg.:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
xs = [1, 1/10, 1/100, 1/1000]
|
||||
f(x) = sin(x)/x
|
||||
[xs f.(xs)]
|
||||
@ -661,14 +667,14 @@ f(x) = sin(x)/x
|
||||
|
||||
Symbolically, `SymPy` provides a `limit` function:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x
|
||||
limit(sin(x)/x, x => 0)
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms h x
|
||||
limit((sin(x+h) - sin(x))/h, h => 0)
|
||||
```
|
||||
@ -678,7 +684,7 @@ limit((sin(x+h) - sin(x))/h, h => 0)
|
||||
There are numeric and symbolic approaches to derivatives. For the numeric approach we use the `ForwardDiff` package, which performs automatic differentiation.
|
||||
|
||||
|
||||
> Derivatives of univariate functions
|
||||
### Derivatives of univariate functions
|
||||
|
||||
Numerically, the `ForwardDiff.derivative(f, x)` function call will find the derivative of the function `f` at the point `x`:
|
||||
|
||||
@ -688,7 +694,7 @@ ForwardDiff.derivative(sin, pi/3) - cos(pi/3)
|
||||
|
||||
The `CalculusWithJulia` package overides the `'` (`adjoint`) syntax for functions to provide a derivative which takes a function and returns a function, so its usage is familiar
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x) = sin(x)
|
||||
f'(pi/3) - cos(pi/3) # or just sin'(pi/3) - cos(pi/3)
|
||||
```
|
||||
@ -696,7 +702,7 @@ f'(pi/3) - cos(pi/3) # or just sin'(pi/3) - cos(pi/3)
|
||||
Higher order derivatives are possible as well,
|
||||
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x) = sin(x)
|
||||
f''''(pi/3) - f(pi/3)
|
||||
```
|
||||
@ -706,7 +712,7 @@ f''''(pi/3) - f(pi/3)
|
||||
|
||||
Symbolically, the `diff` function of `SymPy` finds derivatives.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x
|
||||
f(x) = exp(-x)*sin(x)
|
||||
ex = f(x) # symbolic expression
|
||||
@ -715,28 +721,34 @@ diff(ex, x) # or just diff(f(x), x)
|
||||
|
||||
Higher order derivatives can be specified as well
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x
|
||||
ex = exp(-x)*sin(x)
|
||||
|
||||
diff(ex, x, x)
|
||||
```
|
||||
|
||||
Or with a number:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x
|
||||
ex = exp(-x)*sin(x)
|
||||
|
||||
diff(ex, x, 5)
|
||||
```
|
||||
|
||||
The variable is important, as this allows parameters to be symbolic
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms mu sigma x
|
||||
diff(exp(-((x-mu)/sigma)^2/2), x)
|
||||
```
|
||||
|
||||
> partial derivatives
|
||||
### Partial derivatives
|
||||
|
||||
There is no direct partial derivative function provided by `ForwardDiff`, rather we use the result of the `ForwardDiff.gradient` function, which finds the partial derivatives for each variable. To use this, the function must be defined in terms of a point or vector.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x,y,z) = x*y + y*z + z*x
|
||||
f(v) = f(v...) # this is needed for ForwardDiff.gradient
|
||||
ForwardDiff.gradient(f, [1,2,3])
|
||||
@ -748,7 +760,7 @@ We can see directly that $\partial{f}/\partial{x} = \langle y + z\rangle$. At th
|
||||
|
||||
Symbolically, `diff` is used for partial derivatives:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x y z
|
||||
ex = x*y + y*z + z*x
|
||||
diff(ex, x) # ∂f/∂x
|
||||
@ -758,7 +770,7 @@ diff(ex, x) # ∂f/∂x
|
||||
|
||||
As seen, the `ForwardDiff.gradient` function finds the gradient at a point. In `CalculusWithJulia`, the gradient is extended to return a function when called with no additional arguments:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x,y,z) = x*y + y*z + z*x
|
||||
f(v) = f(v...)
|
||||
gradient(f)(1,2,3) - gradient(f, [1,2,3])
|
||||
@ -766,7 +778,9 @@ gradient(f)(1,2,3) - gradient(f, [1,2,3])
|
||||
|
||||
The `∇` symbol, formed by entering `\nabla[tab]`, is mathematical syntax for the gradient, and is defined in `CalculusWithJulia`.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x,y,z) = x*y + y*z + z*x
|
||||
f(x) = f(x...)
|
||||
∇(f)(1,2,3) # same as gradient(f, [1,2,3])
|
||||
```
|
||||
|
||||
@ -774,7 +788,7 @@ The `∇` symbol, formed by entering `\nabla[tab]`, is mathematical syntax for t
|
||||
|
||||
In `SymPy`, there is no gradient function, though finding the gradient is easy through broadcasting:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x y z
|
||||
ex = x*y + y*z + z*x
|
||||
diff.(ex, [x,y,z]) # [diff(ex, x), diff(ex, y), diff(ex, z)]
|
||||
@ -782,22 +796,28 @@ diff.(ex, [x,y,z]) # [diff(ex, x), diff(ex, y), diff(ex, z)]
|
||||
|
||||
The `CalculusWithJulia` package provides a method for `gradient`:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x y z
|
||||
ex = x*y + y*z + z*x
|
||||
|
||||
gradient(ex, [x,y,z])
|
||||
```
|
||||
|
||||
The `∇` symbol is an alias. It can guess the order of the free symbols, but generally specifying them is needed. This is done with a tuple:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x y z
|
||||
ex = x*y + y*z + z*x
|
||||
|
||||
∇((ex, [x,y,z])) # for this, ∇(ex) also works
|
||||
```
|
||||
|
||||
|
||||
> Jacobian
|
||||
### Jacobian
|
||||
|
||||
The Jacobian of a function $f:R^n \rightarrow R^m$ is a $m\times n$ matrix of partial derivatives. Numerically, `ForwardDiff.jacobian` can find the Jacobian of a function at a point:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(u,v) = [u*cos(v), u*sin(v), u]
|
||||
F(v) = F(v...) # needed for ForwardDiff.jacobian
|
||||
pt = [1, pi/4]
|
||||
@ -808,24 +828,30 @@ ForwardDiff.jacobian(F , pt)
|
||||
|
||||
Symbolically, the `jacobian` function is a method of a *matrix*, so the calling pattern is different. (Of the form `object.method(arguments...)`.)
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms u v
|
||||
F(u,v) = [u*cos(v), u*sin(v), u]
|
||||
F(v) = F(v...)
|
||||
|
||||
ex = F(u,v)
|
||||
ex.jacobian([u,v])
|
||||
```
|
||||
|
||||
As the Jacobian can be identified as the matrix with rows given by the transpose of the gradient of the component, it can be computed directly, but it is more difficult:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms u::real v::real
|
||||
F(u,v) = [u*cos(v), u*sin(v), u]
|
||||
F(v) = F(v...)
|
||||
|
||||
vcat([diff.(ex, [u,v])' for ex in F(u,v)]...)
|
||||
```
|
||||
|
||||
> Divergence
|
||||
### Divergence
|
||||
|
||||
Numerically, the divergence can be computed from the Jacobian by adding the diagonal elements. This is a numerically inefficient, as the other partial derivates must be found and discarded, but this is generally not an issue for these notes. The following uses `tr` (the trace from the `LinearAlgebra` package) to find the sum of a diagonal.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y,z) = [-y, x, z]
|
||||
F(v) = F(v...)
|
||||
pt = [1,2,3]
|
||||
@ -834,7 +860,10 @@ tr(ForwardDiff.jacobian(F , pt))
|
||||
|
||||
The `CalculusWithJulia` package provides `divergence` to compute the divergence and provides the `∇ ⋅` notation (`\nabla[tab]\cdot[tab]`):
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y,z) = [-y, x, z]
|
||||
F(v) = F(v...)
|
||||
|
||||
divergence(F, [1,2,3])
|
||||
(∇⋅F)(1,2,3) # not ∇⋅F(1,2,3) as that evaluates F(1,2,3) before the divergence
|
||||
```
|
||||
@ -844,47 +873,60 @@ divergence(F, [1,2,3])
|
||||
|
||||
Symbolically, the divergence can be found directly:
|
||||
|
||||
```julia;
|
||||
```julia;hold=true
|
||||
@syms x y z
|
||||
ex = F(x,y,z)
|
||||
ex = [-y, x, z]
|
||||
|
||||
sum(diff.(ex, [x,y,z])) # sum of [diff(ex[1], x), diff(ex[2],y), diff(ex[3], z)]
|
||||
```
|
||||
|
||||
The `divergence` function can be used for symbolic expressions:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x y z
|
||||
ex = [-y, x, z]
|
||||
|
||||
divergence(ex, [x,y,z])
|
||||
∇⋅(F(x,y,z), [x,y,z]) # For this, ∇ ⋅ F(x,y,z) also works
|
||||
∇⋅(ex, [x,y,z]) # For this, ∇ ⋅ F(x,y,z) also works
|
||||
```
|
||||
|
||||
> Curl
|
||||
### Curl
|
||||
|
||||
The curl can be computed from the off-diagonal elements of the Jacobian. The calculation follows the formula. The `CalculusWithJulia` package provides `curl` to compute this:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y,z) = [-y, x, 1]
|
||||
F(v) = F(v...)
|
||||
|
||||
curl(F, [1,2,3])
|
||||
```
|
||||
|
||||
As well, if no point is specified, a function is returned for which a point may be specified using 3 coordinates or a vector
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y,z) = [-y, x, 1]
|
||||
F(v) = F(v...)
|
||||
|
||||
curl(F)(1,2,3), curl(F)([1,2,3])
|
||||
```
|
||||
|
||||
Finally, the `∇ ×` (`\nabla[tab]\times[tab]` notation is available)
|
||||
```julia;
|
||||
|
||||
```julia; ohld=true
|
||||
F(x,y,z) = [-y, x, 1]
|
||||
F(v) = F(v...)
|
||||
|
||||
(∇×F)(1,2,3)
|
||||
```
|
||||
|
||||
For symbolic expressions, we have
|
||||
For symbolic expressions, we have the `∇ ×` times notation is available **if** the symbolic vector contains all ``3`` variables
|
||||
|
||||
```
|
||||
∇×F(1,2,3)
|
||||
```
|
||||
```julia; hold=true
|
||||
@syms x y z
|
||||
F = [-y, x, z] # but not [-y, x, 1] which errs; use `curl` with variables specified
|
||||
|
||||
(Do note the subtle difference in the use of parentheses between the numeric and the symbolic. For the symbolic, `F(x,y,z)` is evaluated *before* being passed to `∇×`, where as for the numeric approach `∇×F` is evaluated *before* passing a point to compute the value there.)
|
||||
curl([-y, x, 1], (x,y,z)), ∇×F
|
||||
```
|
||||
|
||||
## Integrals
|
||||
|
||||
@ -894,7 +936,7 @@ Numeric integration is provided by the `QuadGK` package, for univariate integral
|
||||
using QuadGK, HCubature
|
||||
```
|
||||
|
||||
> Integrals of univariate functions
|
||||
### Integrals of univariate functions
|
||||
|
||||
A definite integral may be computed numerically using `quadgk`
|
||||
|
||||
@ -916,7 +958,7 @@ quadgk(x->1/x^(1/2), 0, 1)
|
||||
SymPy provides the `integrate` function to compute both definite and indefinite integrals.
|
||||
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms a::real x::real
|
||||
integrate(exp(a*x)*sin(x), x)
|
||||
```
|
||||
@ -925,28 +967,31 @@ Like `diff` the variable to integrate is specified.
|
||||
|
||||
Definite integrals use a tuple, `(variable, a, b)`, to specify the variable and range to integrate over:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms a::real x::real
|
||||
integrate(sin(a + x), (x, 0, PI)) # ∫_0^PI sin(a+x) dx
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
> 2D and 3D iterated integrals
|
||||
### 2D and 3D iterated integrals
|
||||
|
||||
Two and three dimensional integrals over box-like regions are computed numerically with the `hcubature` function from the `HCubature` package. If the box is $[x_1, y_1]\times[x_2,y_2]\times\cdots\times[x_n,y_n]$ then the limits are specified through tuples of the form $(x_1,x_2,\dots,x_n)$ and $(y_1,y_2,\dots,y_n)$.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x,y) = x*y^2
|
||||
f(v) = f(v...)
|
||||
|
||||
hcubature(f, (0,0), (1, 2)) # computes ∫₀¹∫₀² f(x,y) dy dx
|
||||
```
|
||||
|
||||
The calling pattern for more dimensions is identical.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x,y,z) = x*y^2*z^3
|
||||
f(v) = f(v...)
|
||||
|
||||
hcubature(f, (0,0,0), (1, 2,3)) # computes ∫₀¹∫₀²∫₀³ f(x,y,z) dz dy dx
|
||||
```
|
||||
|
||||
@ -958,7 +1003,7 @@ $$~
|
||||
|
||||
Here we implement this:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x,y) = x*y^2
|
||||
f(v) = f(v...)
|
||||
Phi(r, theta) = r * [cos(theta), sin(theta)]
|
||||
@ -967,26 +1012,18 @@ integrand(rtheta) = f(Phi(rtheta)) * det(ForwardDiff.jacobian(Phi, rtheta))
|
||||
hcubature(integrand, (0.0,-pi/2), (1.0, pi/2))
|
||||
```
|
||||
|
||||
In `CalculusWithJulia` a `fubini` function is provided to compute numeric integrals over regions which can be described by curves represented by functions. E.g., for this problem:
|
||||
|
||||
```julia;
|
||||
CalculusWithJulia.fubini(f, (x -> -sqrt(1-x^2), x -> sqrt(1-x^2)), (0, 1))
|
||||
```
|
||||
|
||||
This function is for convenience, but is not performant. It is not exported, so is used as above, through qualification.
|
||||
|
||||
|
||||
----
|
||||
|
||||
Symbolically, the `integrate` function allows additional terms to be specified. For example, the above could be done through:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x::real y::real
|
||||
integrate(x * y^2, (y, -sqrt(1-x^2), sqrt(1-x^2)), (x, 0, 1))
|
||||
```
|
||||
|
||||
|
||||
> Line integrals
|
||||
### Line integrals
|
||||
|
||||
A line integral of $f$ parameterized by $\vec{r}(t)$ is computed by:
|
||||
|
||||
@ -996,17 +1033,18 @@ $$~
|
||||
|
||||
For example, if $f(x,y) = 2 - x^2 - y^2$ and $r(t) = 1/t \langle \cos(t), \sin(t) \rangle$, then the line integral over $[1,2]$ is given by:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
f(x,y) = 2 - x^2 - y^2
|
||||
f(v) = f(v...)
|
||||
r(t) = [cos(t), sin(t)]/t
|
||||
|
||||
integrand(t) = (f∘r)(t) * norm(r'(t))
|
||||
quadgk(integrand, 1, 2)
|
||||
```
|
||||
|
||||
To integrate a line integral through a vector field, say $\int_C F \cdot\hat{T} ds=\int_C F\cdot \vec{r}'(t) dt$ we have, for example,
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y) = [-y, x]
|
||||
F(v) = F(v...)
|
||||
r(t) = [cos(t), sin(t)]/t
|
||||
@ -1018,23 +1056,24 @@ quadgk(integrand, 1, 2)
|
||||
|
||||
Symbolically, there is no real difference from a 1-dimensional integral. Let $\phi = 1/\|r\|$ and integrate the gradient field over one turn of the helix $\vec{r}(t) = \langle \cos(t), \sin(t), t\rangle$.
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
@syms x::real y::real z::real t::real
|
||||
phi(x,y,z) = 1/sqrt(x^2 + y^2 + z^2)
|
||||
r(t) = [cos(t), sin(t), t]
|
||||
∇phi = diff.(phi(x,y,z), [x,y,z])
|
||||
∇phi_r = subs.(∇phi, x.=> r(t)[1], y.=>r(t)[2], z.=>r(t)[3])
|
||||
rp = diff.(r(t), t)
|
||||
ex = simplify(∇phi_r ⋅ rp )
|
||||
global helix = simplify(∇phi_r ⋅ rp )
|
||||
```
|
||||
|
||||
Then
|
||||
|
||||
```julia;
|
||||
integrate(ex, (t, 0, 2PI))
|
||||
@syms t::real
|
||||
integrate(helix, (t, 0, 2PI))
|
||||
```
|
||||
|
||||
> Surface integrals
|
||||
### Surface integrals
|
||||
|
||||
|
||||
The surface integral for a parameterized surface involves a surface element $\|\partial\Phi/\partial{u} \times \partial\Phi/\partial{v}\|$. This can be computed numerically with:
|
||||
@ -1061,9 +1100,9 @@ Symbolically, the approach is similar:
|
||||
|
||||
```julia;
|
||||
@syms u::real v::real
|
||||
ex = Phi(u,v)
|
||||
J = ex.jacobian([u,v])
|
||||
SurfEl = norm(J[:,1] × J[:,2]) |> simplify
|
||||
exₚ = Phi(u,v)
|
||||
Jₚ = exₚ.jacobian([u,v])
|
||||
SurfEl = norm(Jₚ[:,1] × Jₚ[:,2]) |> simplify
|
||||
```
|
||||
|
||||
Then
|
||||
@ -1074,8 +1113,8 @@ integrate(SurfEl, (u, 0, 1), (v, 0, 2PI))
|
||||
|
||||
Integrating a vector field over the surface, would be similar:
|
||||
|
||||
```julia;
|
||||
```julia; hold=true
|
||||
F(x,y,z) = [x, y, z]
|
||||
ex = F(Phi(u,v)...) ⋅ (J[:,1] × J[:,2])
|
||||
ex = F(Phi(u,v)...) ⋅ (Jₚ[:,1] × Jₚ[:,2])
|
||||
integrate(ex, (u,0,1), (v, 0, 2PI))
|
||||
```
|
||||
|
@ -325,7 +325,7 @@ This is a work in progress. To report an issue, make a comment, or suggest somet
|
||||
To make edits to the documents directly, a pull request with the modified `*.jmd` files in the `CwJ` directory should be made. Minor edits to the `*.jmd` files should be possible through the GitHub web interface. In the footer of each page a pencil icon (like the one below) when clicked should cause the opening of the corresponding `*.jmd` file on GitHub for suggesting modifications. The html files will be generated independently, that need not be done.
|
||||
|
||||
|
||||
```julia; echo=false
|
||||
```julia; hold=true; echo=false
|
||||
# put in a custom footer
|
||||
txt = """
|
||||
<div class="card" style="">
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Usages of unicode symbols
|
||||
# Usages of Unicode symbols
|
||||
|
||||
|
||||
`Julia` allows the use of *unicode* symbols to replace variable names and for function calls. Unicode operations are entered in this pattern `\name[tab]`. That is a slash, `\`, the name (e.g., `alpha`), and then a press of the `tab` key.
|
||||
`Julia` allows the use of *Unicode* symbols to replace variable names and for function calls. Unicode operations are entered in this pattern `\name[tab]`. That is a slash, `\`, the name (e.g., `alpha`), and then a press of the `tab` key.
|
||||
|
||||
In these notes, the following may appear as variable or function names
|
||||
|
||||
|
22
docs/make.jl
22
docs/make.jl
@ -58,20 +58,20 @@ force = parse(Bool, d["force"])
|
||||
|
||||
|
||||
if isnothing(folder) && isnothing(file)
|
||||
# # build full thing
|
||||
# build full thing
|
||||
# for folder ∈ ("precalc", "limits", "derivatives", "integrals", "ODEs",
|
||||
# "differentiable_vector_calculus", "integral_vector_calculus")
|
||||
# "differentiable_vector_calculus", "integral_vector_calculus",
|
||||
# "misc")
|
||||
# build_pages(folder, nothing, target, force)
|
||||
# end
|
||||
# # alternatives needs work
|
||||
# build_pages("alternatives", "plotly_plotting", "html", force)
|
||||
|
||||
|
||||
# # others need to integrate with Pluto
|
||||
# for folder ∈ ("alternatives", "misc")
|
||||
# build_pages(folder, nothing, "weave_html", force)
|
||||
# end
|
||||
# keep it simple for now; uncomment above once build goes through
|
||||
build_pages("precalc", "functions", "html", true)
|
||||
build_pages("misc", nothing, "weave_html", true)
|
||||
|
||||
build_toc()
|
||||
|
||||
else
|
||||
build_pages(folder, file, target, force)
|
||||
end
|
||||
@ -86,7 +86,7 @@ end
|
||||
# Documenter can also automatically deploy documentation to gh-pages.
|
||||
# See "Hosting Documentation" and deploydocs() in the Documenter manual
|
||||
# for more information.
|
||||
|
||||
Documenter.deploydocs(
|
||||
repo = "github.com/jverzani/CalculusWithJuliaNotes.jl"
|
||||
Documenter.deploydocs(;
|
||||
repo = "github.com/jverzani/CalculusWithJuliaNotes.jl",
|
||||
push_preview=true
|
||||
)
|
||||
|
@ -8,14 +8,38 @@ const htmlfile = joinpath(@__DIR__, "..", "templates", "bootstrap.tpl")
|
||||
const latexfile = joinpath(@__DIR__, "..", "templates", "julia_tex.tpl")
|
||||
|
||||
function build_toc(force=true)
|
||||
infile = joinpath(repo_directory, "CwJ", "misc", "toc.jmd")
|
||||
outfile = joinpath(@__DIR__, "build", "index.html")
|
||||
weave(infile;
|
||||
out_path=outfile,
|
||||
doctype="md2html",
|
||||
fig_ext=".svg",
|
||||
template=htmlfile,
|
||||
fig_path=tempdir())
|
||||
@info "building table of contents"
|
||||
|
||||
jmd_dir = joinpath(repo_directory, "CwJ", "misc")
|
||||
build_dir = joinpath(@__DIR__, "build")
|
||||
isdir(build_dir) || mkpath(build_dir)
|
||||
|
||||
file = joinpath(jmd_dir, "toc.jmd")
|
||||
|
||||
outfile = joinpath(build_dir, "index.html")
|
||||
|
||||
cd(jmd_dir)
|
||||
|
||||
build_file(file, outfile, force=force) || return nothing
|
||||
|
||||
header = CalculusWithJulia.WeaveSupport.header_cmd
|
||||
#footer = CalculusWithJulia.WeaveSupport.footer_cmd(bnm, folder)
|
||||
html_content = md2html(file,
|
||||
header_cmds=(header,),
|
||||
footer_cmds=()
|
||||
)
|
||||
|
||||
open(outfile, "w") do io
|
||||
write(io, html_content)
|
||||
end
|
||||
|
||||
# to use weave, not pluto
|
||||
# weave(file;
|
||||
# out_path=outfile,
|
||||
# doctype="md2html",
|
||||
# fig_ext=".svg",
|
||||
# template=htmlfile,
|
||||
# fig_path=tempdir())
|
||||
end
|
||||
|
||||
|
||||
@ -31,10 +55,11 @@ end
|
||||
# build list ⊂ (:script,:html,:weave_html, :pdf,:github,:notebook,:pluto)
|
||||
function weave_file(folder, file; build_list=(:html,), force=false, kwargs...)
|
||||
|
||||
jmd_dir = isdir(folder) ? folder : joinpath(repo_directory,"CwJ",folder)
|
||||
jmd_dir = isdir(folder) ? folder : joinpath(repo_directory, "CwJ", folder)
|
||||
jmd_file = joinpath(jmd_dir, file)
|
||||
bnm = replace(basename(jmd_file), r".jmd$" => "")
|
||||
build_dir = joinpath(repo_directory, "docs", "build")
|
||||
build_dir = joinpath(@__DIR__, "build")
|
||||
isdir(build_dir) || mkpath(build_dir)
|
||||
|
||||
if !force
|
||||
#testfile = joinpath(repo_directory, "html", folder, bnm*".html")
|
||||
|
Loading…
x
Reference in New Issue
Block a user