{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Julia v1.1.0 の Windows 8.1 へのインストール\n", "\n", "* Author: 黒木 玄\n", "* Date: 2019-03-18~2019-04-05\n", "* Repository: https://github.com/genkuroki/msfd28\n", "\n", "このファイルは次の研究集会での講演後に追加の資料として作成された:\n", "\n", "* [数学ソフトウェアとフリードキュメント XXVIII](http://www.mathlibre.org/msfd/28-ja.html)\n", "* 2019年3月16日(土) 13:00–18:00\n", "* 東京工業大学 大岡山キャンパス 本館1階H116講義室\n", "\n", "このファイルは[nbviewerで読める](https://nbviewer.jupyter.org/github/genkuroki/msfd28/blob/master/install.ipynb).\n", "\n", "[Julia](https://julialang.org/)+[Jupyter](https://jupyter.org/)を最も楽に使う方法は\n", "\n", "* [JuliaBox](https://juliabox.com/)\n", "\n", "を使うことである. ブラウザを使える環境ならどこでも使える. JuliaBox内にJulia言語のチュートリアルがある.\n", "\n", "しかし, 自分のパソコン内でJulia+Jupyterの環境が構築されていると非常に便利である. このノートでは私が Windows 8.1 に Julia+Jupyter を入れたときの操作の仕方を解説する.\n", "\n", "次のファイルも参照せよ:\n", "\n", "* [JuliaとJupyterのすすめ](https://nbviewer.jupyter.org/github/genkuroki/msfd28/blob/master/msfd28genkuroki.ipynb)\n", "\n", "Julia言語については[公式ドキュメント](https://docs.julialang.org/en/v1/)が結構懇切丁寧でわかりやすい. 次のチュートリアルもおすすめである:\n", "\n", "* [Julia高速チュートリアル](https://github.com/bicycle1885/Julia-Tutorial)" ] }, { "cell_type": "markdown", "metadata": { "toc": true }, "source": [ "

目次

\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Julia+Jupyterの環境整備\n", "\n", "Julia + Jupyter の組み合わせで,\n", "\n", "* Julia言語で書かれたプログラムのコード\n", "* その計算結果 (グラフのプロットや動画などを含む)\n", "* MathJaxで整形された数式を含むmarkdownで書かれた文書\n", "\n", "の3つを1つのファイルの中に詰め込むことができる. これは非常に便利である. Jupyter では Python, R, Ruby なども使用可能である.\n", "\n", "Windows 8.1 にJuliaとJupyterを入れる. 使用するブラウザはChromeである.\n", "\n", "### Juliaの公式バイナリのダウンロード\n", "\n", "(1) [Julia Downloads](https://julialang.org/downloads/) から Windows Self-Extracting Archive 64 bit をダウンロードしてインストール. インストール先は C:\\Julia-1.1.0\n", "\n", "### Juliaのパッケージモードへの入り方\n", "\n", "(2) julia.exe を起動.\n", "\n", "```julia\n", "julia>\n", "```\n", "\n", "というプロンプトが出る. パッケージモードに移動するには `]` を押す. プロンプトは\n", "\n", "```Julia\n", "(v1.1) pkg>\n", "```\n", "\n", "に変わる. 以下 `pkg>` と略記する. パッケージモードからもとに戻るには行頭でバックスペースを押す.\n", "\n", "### IJuliaのインストール\n", "\n", "(3) [IJulia.jl](https://github.com/JuliaLang/IJulia.jl)のインストール\n", "\n", "IJulia.jl は Julia を Jupyter notebook で使用するためのパッケージである. \n", "\n", "```julia\n", "julia> ENV[\"JUPYTER\"] = \"\" # Juliaでインストールしたminiconda内のJupyterを使う設定\n", "pkg> add IJulia\n", "pkg> build IJulia\n", "julia> using IJulia\n", "julia> notebook(detached=true)\n", "install Jupyter via Conda, y/n? [y]: y\n", "```\n", "\n", "これでJupyterの環境がJulia内から管理できるminiconda(Python環境)内にインストールされる.\n", "\n", "

\n", "\n", "私の環境ではChromeにlocalhost:8888/treeの空白のタブが開くというトラブルが発生した.\n", "\n", "

\n", "

\n", "\n", "この空白タブ発生の問題を下の方ではminiconda内のnotebookのバージョンダウンで解決する.\n", "\n", "**追記(2019-03-26):** 別のWindows 8.1機で上と同じ作業を繰り返したら, 空白タブ発生が起こらなかった. そのような場合には次の(4)のステップをとばしてよい.\n", "\n", "Juliaでインストールしたminiconda内のjupyter.exeではなく, 外部の例えば C:\\Anaconda3\\Scripts\\jupyter.exe を使用するならば最初の行を次のように変える.\n", "\n", "```julia\n", "julia> ENV[\"JUPYTER\"] = \"C:\\\\Anaconda3\\\\Scripts\\\\jupyter.exe\"\n", "```\n", "\n", "私の環境では, Jupyterの設定ファイル群は /Users/genkuroki/AppData/Roaming/jupyter 以下に置かれている.\n", "\n", "### ブラウザに空白タブが開いた場合の対処の仕方\n", "\n", "(4) [Conda.jl](https://github.com/JuliaPy/Conda.jl)でnotebookをバージョンダウンする.\n", "\n", "Conda.jl を使えば Julia で `~/.julia/conda/3` 以下にインストールした miniconda (Python) のライブラリを管理できる.\n", "\n", "miniconda の notebook のバージョンダウンをする理由は上の「Chromeにおける空白タブ」の問題の解決と, Nbextensions の導入を確実にするためにである. もしもその2つの問題が解決済みならばバージョンダウンを実行する必要はない.\n", "\n", "```julia\n", "pkg> add Conda\n", "julia> using Conda\n", "julia> Conda.add_channel(\"defaults\") # この行は必ずしも必要ない\n", "julia> Conda.add(\"notebook=5.6.0\")\n", "```\n", "\n", "

\n", "

\n", "\n", "これでJupyter notebookが普通に使えるようになった.\n", "\n", "### NbextensionsとRISEのインストール\n", "\n", "(5) 続けて, [Nbextensions](https://github.com/ipython-contrib/jupyter_contrib_nbextensions)と[RISE](https://github.com/damianavila/RISE)をインストール.\n", "\n", "NbextensionsはJupyter notebookを便利に使うためにはほぼ必須の拡張群である. RISEはJupyter notebookでプレゼンも可能にするための拡張である. どちらも必須だと思っておいた方がよい.\n", "\n", "```julia\n", "julia> using Conda\n", "julia> Conda.add_channel(\"conda-forge\")\n", "julia> Conda.add(\"jupyter_contrib_nbextensions\")\n", "julia> Conda.add(\"rise\")\n", "```\n", "\n", "以上で Jupyter notebook + Nbextensions + RISE を使える環境が完成した.\n", "\n", "

\n", "\n", "

\n", "\n", "動作確認のためには julia.exe を立ち上げ直して, \n", "\n", "```julia\n", "julia> using IJulia\n", "julia> notebook(detached=true)\n", "```\n", "\n", "を実行する.\n", "\n", "### Jupyter notebook 起動用のバッチファイルの作成\n", "\n", "(6) 次の内容の[バッチファイル](https://gist.github.com/genkuroki/c003cf520df464abbc0cd5876fa99706)を作成.\n", "\n", "```\n", "C:\\Users\\genkuroki\\.julia\\conda\\3\\python.exe C:\\Users\\genkuroki\\.julia\\conda\\3\\cwp.py C:\\Users\\genkuroki\\.julia\\conda\\3 \"C:/Users/genkuroki/.julia/conda/3/python.exe\" \"C:/Users/genkuroki/.julia/conda/3/Scripts/jupyter-notebook-script.py\" \"C:\\Users\\genkuroki\\OneDrive\"\n", "pause\n", "```\n", "\n", "このバッチファイルを実行すると, ChromeにJupyter notebookのタブが開く.\n", "\n", "上のバッチファイルは私専用なので, 自分に合わせて書き直して使用すること." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PyCall, PyPlot, SymPyをインストール\n", "\n", "(1) [PyCall.jl](https://github.com/JuliaPy/PyCall.jl)\n", "\n", "PyCall.jl はJulia言語内で Python を利用するために使われるパッケージである.\n", "\n", "```julia\n", "julia> ENV[\"PYTHON\"] = \"\" # minicondaのpython.exeを使うための設定\n", "pkg> add PyCall\n", "pkg> build PyCall\n", "julia> using PyCall\n", "julia> PyCall.python\n", "\"C:\\\\Users\\\\genkuroki\\\\.julia\\\\conda\\\\3\\\\python.exe\"\n", "```\n", "\n", "Julia でインストールしたminiconda内のPythonではなく, 外部の例えば C:\\Anaconda3\\python.exe を使うならば, 最初の行を\n", "\n", "```julia\n", "julia> ENV[\"PYTHON\"] = \"C:\\\\Anaconda3\\\\python.exe\"\n", "```\n", "\n", "に変える.\n", "\n", "(2) [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl)\n", "\n", "PyPlot.jl は Python の [matplotlib](https://matplotlib.org/) を使って作画するためのパッケージである. 一般に作画パッケージの使い方を覚える学習コストは非常に高い. PyPlot.jl を使えば Python で標準的に使われている matplotlib の使用経験があれば Julia でもほぼ同じコードでグラフをプロットできるようになる. ただし, Julia言語で文字列は Python 風の '文字列' の形式ではなく \"文字列\" の形式で書き, True, False は true, false と書く. このような書き換えは必要である. \n", "\n", "```julia\n", "pkg> add PyPlot\n", "julia> using PyPlot\n", "```\n", "\n", "自動的にCondaによってmatplotlib関連のPythonライブラリがインストールされる.\n", "\n", "(3) [SymPy.jl](https://github.com/JuliaPy/SymPy.jl)\n", "\n", "SymPy.jl は Python 環境の数式処理系 sympy をJulia言語内から使うためのパッケージである.\n", "\n", "```julia\n", "pkg> add SymPy\n", "julia> using SymPy\n", "```\n", "\n", "自動的にCondaによってsympy関連がインストールされる." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 自分が使いたいパッケージを自由に入れる\n", "\n", "**追加**\n", "\n", "```julia\n", "pkg> add DifferentialEquations\n", "```\n", "\n", "**削除**\n", "\n", "```julia\n", "pkg> rm Distributions\n", "```\n", "\n", "**インストールしたパッケージのリスト**\n", "\n", "```julia\n", "pkg> st\n", "```\n", "\n", "**プレコンパイル**\n", "\n", "```julia\n", "pkg> precompile\n", "```\n", "\n", "**アップデート**\n", "\n", "```julia\n", "pkg> up\n", "```\n", "\n", "**ヘルプ**\n", "\n", "```julia\n", "pkg> help\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Nbextensionsの設定\n", "\n", "### Live Markdown Preview\n", "\n", "Nbextensions の Live Markdown Preview を使えば, LaTeX方式で書かれた数式やmarkdownによるマークアップをリアルタイムで整形した結果を見ながらmarkdownを変数することができる. 文書を書くときにはほぼ必須の機能である.\n", "\n", "Jupyter の Nbextensions のタブで Live Markdown Preview の項目にチェックを入れれば使えるようになる.\n", "\n", "### RISE\n", "\n", "RISEはJupyter notebookでプレゼンするために使える拡張である. 詳しい使い方については\n", "\n", "* [スライド上でコードが動く!Jupyter+RISEによるプレゼン環境](http://codecrafthouse.jp/p/2017/05/jupyter-rise-live-presentation/)\n", "\n", "を参照せよ.\n", "\n", "Jupyter の Nbextensions のタブで RISE の項目にチェックを入れれば使えるようになる.\n", "\n", "### Table of Contents (2)\n", "\n", "Table of Contents (2) を使えば Jupyter notebook に自動的に更新される目次を付けることができる.\n", "\n", "Jupyter の Nbextensions のタブでその項目にチェックを入れれば使えるようになる.\n", "\n", "### Gist-it\n", "\n", "Nbextensions の Gist-it を使えば, 手元のパソコン上で書いたJupyterノートブックをほとんどワンボタンで [GitHub Gist](https://gist.github.com/) に投稿して公開することができる. すでに公開したものの更新も Gist-it によって可能である.\n", "\n", "(1) [GitHub](https://github.com/) のアカウントを取得する.\n", "\n", "\n", "(2) [GitHub「Personal access tokens」の設定方法](https://qiita.com/kz800/items/497ec70bff3e555dacd0)を読んで, GitHub のパーソナルアクセストークンを取得する.\n", "\n", "\n", "(3) JupyterのNbextensionsタブで, Gist-itにチェックを入れる.\n", "\n", "

\n", "\n", "\n", "(4) Gist-it の詳細設定の \"Github personal access token\" に上で取得したトークンを貼り付け, \"Gists default to public\" にチェックを入れる. \n", "\n", "

\n", "\n", "\n", "(5) これで各ノートブックの \"Create/Edit Gist of notebook\" のボタンを使用可能になる. そのボタンを押すことによって [GitHub Gist](https://gist.github.com/) でノートブックを公開し, 簡単なバージョン管理もできるようになる.\n", "\n", "

\n", "\n", "\n", "(6) インターネット上で公開されたJupyterノートブックのURLを [nbviewer](https://nbviewer.jupyter.org/) に貼り付けることによって, GitHubのサイトよりもきれいに成形されたノートブックを閲覧できるようになる. (キャッシュが生成されるが、そのキャッシュを無視したい場合には最後に `?flushcache=true` を付ける.\n", "\n", "\n", "以上の手続きによって, 非除に気軽に Jupyter 上で書いたノートブックを公開できるようになる." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## パッケージの簡単な使用例" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### PyCall.jl で Python を利用\n", "\n", "[PyCall.jl](https://github.com/JuliaPy/PyCall.jl) を使えばPythonの機能をかなり自由にJuliaでも利用できる.\n", "\n", "まだ Julia からインストールした miniconda に scipy をインストールしていない場合には以下のセルを実行する. 私の環境ではすでにインストール済みだと表示される. Anaconda3 の python を利用している場合には scipy などのメジャーなライブラリは最初から入っている." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "┌ Info: Running `conda install -y scipy` in root environment\n", "└ @ Conda C:\\Users\\genkuroki\\.julia\\packages\\Conda\\CpuvI\\src\\Conda.jl:112\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Collecting package metadata: ...working... done\n", "Solving environment: ...working... done\n", "\n", "## Package Plan ##\n", "\n", " environment location: C:\\Users\\genkuroki\\.julia\\conda\\3\n", "\n", " added / updated specs:\n", " - scipy\n", "\n", "\n", "The following packages will be downloaded:\n", "\n", " package | build\n", " ---------------------------|-----------------\n", " conda-4.6.11 | py36_0 1.7 MB\n", " ------------------------------------------------------------\n", " Total: 1.7 MB\n", "\n", "The following packages will be UPDATED:\n", "\n", " conda 4.6.8-py36_0 --> 4.6.11-py36_0\n", "\n", "\n", "\n", "Downloading and Extracting Packages\n", "conda-4.6.11 | 1.7 MB | ########## | 100% \n", "Preparing transaction: ...working... done\n", "Verifying transaction: ...working... done\n", "Executing transaction: ...working... done\n" ] } ], "source": [ "using Conda\n", "Conda.add(\"scipy\")" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(\"C:\\\\Users\\\\genkuroki\\\\.julia\\\\conda\\\\3\\\\python.exe\", v\"3.6.5\")" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using PyCall\n", "PyCall.python, PyCall.pyversion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "上のセルでは使用する python.exe とそのバージョンを表示させた." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "x₀ は `x\\_0` と入力してTABを押せば入力可能である." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.7390851332151607" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "so = pyimport(\"scipy.optimize\")\n", "x₀ = so.newton(x -> cos(x) - x, 1)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cos(x₀) - x₀" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`pyimport(\"scipy.optimize\")` の代わりに, `pyimport_conda(\"scipy.optimize\", \"scipy\")` を使えば, 自動的に miniconda 環境に scipy がインストールされる. 詳しくは [Using PyCall from Julia Modules](https://github.com/JuliaPy/PyCall.jl#using-pycall-from-julia-modules) を参照." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### PyPlot.jl でプロット" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 4.680144 seconds (6.21 M allocations: 305.032 MiB, 3.34% gc time)\n" ] } ], "source": [ "@time using PyPlot: PyPlot, plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Code セルにおいて π は `\\pi` の後にタブを押すと入力される. " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "PyPlot.Figure(PyObject
)" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ " 0.562841 seconds (1.33 M allocations: 66.538 MiB, 3.50% gc time)\n", " 0.068644 seconds (171.93 k allocations: 8.509 MiB, 8.86% gc time)\n" ] } ], "source": [ "x = range(-3π, 3π, length=400)\n", "plt.figure(figsize=(4,2))\n", "@time plt.plot(x, sin.(x))\n", "@time plt.plot(x, cos.(x))\n", "plt.grid(ls=\":\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### SymPy.jl で数式処理\n", "\n", "sympyの詳しい解説については[Python版のsympyの解説](https://www.sympy.org)を参照すればよい.\n", "\n", "ただし, 'string' → \"string\" や True, False → true, false などの書き換えは必要になる." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 6.864220 seconds (10.79 M allocations: 535.044 MiB, 4.20% gc time)\n" ] } ], "source": [ "@time using SymPy: SymPy, sympy, Sym, @vars, PI, oo" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$$\\int_{0}^{\\infty} e^{- a x^{r}}\\, dx=a^{- \\frac{1}{r}} \\Gamma\\left(1 + \\frac{1}{r}\\right)$$" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "@vars x\n", "@vars a r positive=true\n", "I = sympy.Integral(exp(-a*x^r), (x, 0, oo))\n", "display(\"text/html\", \n", " raw\"$$\" * \n", " sympy.latex(I) * \"=\" * sympy.latex(I.doit().simplify())\n", " * raw\"$$\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia言語では文字列の連結には `*` を使う." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plots.jl gr() バックエンドでプロット\n", "\n", "[Plots.jl](https://github.com/JuliaPlots/Plots.jl) は上で紹介した [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) と共に, Julia言語でよく使われている作画パッケージである. Plots.jl では複数のバックエンドを切り替えて使うことができる. 以下では [gr()](http://docs.juliaplots.org/latest/examples/gr/) バックエンドを使う. 他にも [pyplot()](http://docs.juliaplots.org/latest/examples/pyplot/), [plotlyjs()](http://docs.juliaplots.org/latest/examples/plotlyjs/) などがある.\n", "\n", "次のセルのように, 先頭が `]` のCodeセルではパッケージモードのコマンドが実行される. この機能を使えば, Jupyterノートブックの中でパッケージ管理をある程度できる. 次のセルではもしも Plots パッケージがインストールされていないならばインストールされる." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m registry at `C:\\Users\\genkuroki\\.julia\\registries\\General`\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m git-repo `https://github.com/JuliaRegistries/General.git`\n", "\u001b[?25l\u001b[2K\u001b[?25h\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Project.toml`\n", "\u001b[90m [no changes]\u001b[39m\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Manifest.toml`\n", "\u001b[90m [no changes]\u001b[39m\n" ] } ], "source": [ "]add Plots" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 8.599652 seconds (15.73 M allocations: 800.354 MiB, 5.03% gc time)\n" ] } ], "source": [ "@time using Plots" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 17.279587 seconds (41.83 M allocations: 2.038 GiB, 8.41% gc time)\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "-15\n", "\n", "\n", "-10\n", "\n", "\n", "-5\n", "\n", "\n", "0\n", "\n", "\n", "5\n", "\n", "\n", "10\n", "\n", "\n", "15\n", "\n", "\n", "-2\n", "\n", "\n", "-1\n", "\n", "\n", "0\n", "\n", "\n", "1\n", "\n", "\n", "2\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "sin\n", "\n", "\n", "\n", "cos\n", "\n", "\n", "\n", "tan\n", "\n", "\n", "\n", "cot\n", "\n", "\n" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gr(legend=:bottomright, size=(600,200))\n", "## cutted(f) = f # safefuncを無効にすると縦に余計な線が入る\n", "cutted(f; M=5) = (x -> (y = f(x); abs(y) > M ? typeof(y)(NaN) : y))\n", "interval = range(-5π, 5π, length=400)\n", "funcs = [sin, cos, tan, cot]\n", "@time plot(cutted.(funcs), interval, ylim=(-2, 2), label=[\"sin\", \"cos\", \"tan\", \"cot\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "上のセルでのプロットに長大な時間がかかっているように見えるのは, プロット関係の函数群のコンパイルが just-in-time で実行されているからである. 実行したいプログラムのコードの入力を始める前に `plot(sin)` などを実行しておけば, コードの入力が終わる頃にはプロット関係の函数がコンパイルされており, すぐにプロットできるようになっていて便利である." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "以下のように[アニメーションの作成](http://docs.juliaplots.org/latest/animations/)も容易である." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 8.146110 seconds (43.53 M allocations: 1.154 GiB, 4.06% gc time)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "┌ Info: Saved animation to \n", "│ fn = C:\\Users\\genkuroki\\OneDrive\\msfd28\\sin-cos.gif\n", "└ @ Plots C:\\Users\\genkuroki\\.julia\\packages\\Plots\\47Tik\\src\\animation.jl:90\n" ] }, { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using Base64\n", "showgif(fn) = open(fn) do f\n", " b = base64encode(f)\n", " display(\"text/html\", \"\"\"\"\"\")\n", "end\n", "\n", "gr(size=(600, 200), legend=:bottomright)\n", "ENV[\"PLOTS_TEST\"] = \"true\"\n", "\n", "interval = range(1, 20, length=100)\n", "@time anim = @animate for a in 2π*[interval; reverse(interval)] \n", " x = range(0, a, length=400)\n", " plot(x, [sin.(x), cos.(x)], label=[\"sin\", \"cos\"], ylim=(-1.1, 1.1))\n", "end\n", "\n", "gifname = \"sin-cos.gif\"\n", "gif(anim, gifname, fps = 15)\n", "sleep(0.1)\n", "showgif(gifname)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "上で `ENV[\"PLOTS_TEST\"] = \"true\"` とした理由について [Incosistency of image size across different backends (GR != others) #1355](https://github.com/JuliaPlots/Plots.jl/issues/1355) を参照せよ. `sleep(0.1)` は結果の表示のタイミングの調節のために挿入してある." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 確率分布や統計データを扱う\n", "\n", "以下では [Distributions.jl](https://github.com/JuliaStats/Distributions.jl), [StatsPlots.jl](https://github.com/JuliaPlots/StatsPlots.jl), [RDataSets.jl](https://github.com/johnmyleswhite/RDatasets.jl) を使用する." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Project.toml`\n", "\u001b[90m [no changes]\u001b[39m\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Manifest.toml`\n", "\u001b[90m [no changes]\u001b[39m\n" ] } ], "source": [ "]add Distributions" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Project.toml`\n", "\u001b[90m [no changes]\u001b[39m\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Manifest.toml`\n", "\u001b[90m [no changes]\u001b[39m\n" ] } ], "source": [ "]add StatsPlots" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Project.toml`\n", "\u001b[90m [no changes]\u001b[39m\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Manifest.toml`\n", "\u001b[90m [no changes]\u001b[39m\n" ] } ], "source": [ "]add KernelDensity" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Project.toml`\n", "\u001b[90m [no changes]\u001b[39m\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Manifest.toml`\n", "\u001b[90m [no changes]\u001b[39m\n" ] } ], "source": [ "]add RDatasets" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 8.601229 seconds (20.00 M allocations: 989.745 MiB, 7.51% gc time)\n" ] }, { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "-5\n", "\n", "\n", "0\n", "\n", "\n", "5\n", "\n", "\n", "10\n", "\n", "\n", "15\n", "\n", "\n", "0.00\n", "\n", "\n", "0.05\n", "\n", "\n", "0.10\n", "\n", "\n", "0.15\n", "\n", "\n", "0.20\n", "\n", "\n", "0.25\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Normal(5, 3)\n", "\n", "\n", "\n", "Gamma(5, 0.7)\n", "\n", "\n" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Distributions\n", "using StatsPlots\n", "gr(legend=:topright, size=(400, 240))\n", "normaldist = Normal(5.0, 3.0) # μ = 5.0, σ = 3.0\n", "gammadist = Gamma(5.0, 0.7) # α = 5.0, θ = 0.7 \n", "@time plot([normaldist, gammadist], label=[\"Normal(5, 3)\", \"Gamma(5, 0.7)\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "次のセルのように, 先頭が `?` のCodeセルではヘルプが表示される." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "search: \u001b[0m\u001b[1mG\u001b[22m\u001b[0m\u001b[1ma\u001b[22m\u001b[0m\u001b[1mm\u001b[22m\u001b[0m\u001b[1mm\u001b[22m\u001b[0m\u001b[1ma\u001b[22m \u001b[0m\u001b[1mg\u001b[22m\u001b[0m\u001b[1ma\u001b[22m\u001b[0m\u001b[1mm\u001b[22m\u001b[0m\u001b[1mm\u001b[22m\u001b[0m\u001b[1ma\u001b[22mdist \u001b[0m\u001b[1mg\u001b[22m\u001b[0m\u001b[1ma\u001b[22m\u001b[0m\u001b[1mm\u001b[22mut\u001b[0m\u001b[1mm\u001b[22m\u001b[0m\u001b[1ma\u001b[22mx Inverse\u001b[0m\u001b[1mG\u001b[22m\u001b[0m\u001b[1ma\u001b[22m\u001b[0m\u001b[1mm\u001b[22m\u001b[0m\u001b[1mm\u001b[22m\u001b[0m\u001b[1ma\u001b[22m \u001b[0m\u001b[1mg\u001b[22m\u001b[0m\u001b[1ma\u001b[22m\u001b[0m\u001b[1mm\u001b[22mut\u001b[0m\u001b[1mm\u001b[22min\n", "\n" ] }, { "data": { "text/latex": [ "\\begin{verbatim}\n", "Gamma(α,θ)\n", "\\end{verbatim}\n", "The \\emph{Gamma distribution} with shape parameter \\texttt{α} and scale \\texttt{θ} has probability density function\n", "\n", "$$f(x; \\alpha, \\theta) = \\frac{x^{\\alpha-1} e^{-x/\\theta}}{\\Gamma(\\alpha) \\theta^\\alpha},\n", "\\quad x > 0$$\n", "\\begin{verbatim}\n", "Gamma() # Gamma distribution with unit shape and unit scale, i.e. Gamma(1, 1)\n", "Gamma(α) # Gamma distribution with shape α and unit scale, i.e. Gamma(α, 1)\n", "Gamma(α, θ) # Gamma distribution with shape α and scale θ\n", "\n", "params(d) # Get the parameters, i.e. (α, θ)\n", "shape(d) # Get the shape parameter, i.e. α\n", "scale(d) # Get the scale parameter, i.e. θ\n", "\\end{verbatim}\n", "External links\n", "\n", "\\begin{itemize}\n", "\\item \\href{http://en.wikipedia.org/wiki/Gamma_distribution}{Gamma distribution on Wikipedia}\n", "\n", "\\end{itemize}\n" ], "text/markdown": [ "```\n", "Gamma(α,θ)\n", "```\n", "\n", "The *Gamma distribution* with shape parameter `α` and scale `θ` has probability density function\n", "\n", "$$\n", "f(x; \\alpha, \\theta) = \\frac{x^{\\alpha-1} e^{-x/\\theta}}{\\Gamma(\\alpha) \\theta^\\alpha},\n", "\\quad x > 0\n", "$$\n", "\n", "```julia\n", "Gamma() # Gamma distribution with unit shape and unit scale, i.e. Gamma(1, 1)\n", "Gamma(α) # Gamma distribution with shape α and unit scale, i.e. Gamma(α, 1)\n", "Gamma(α, θ) # Gamma distribution with shape α and scale θ\n", "\n", "params(d) # Get the parameters, i.e. (α, θ)\n", "shape(d) # Get the shape parameter, i.e. α\n", "scale(d) # Get the scale parameter, i.e. θ\n", "```\n", "\n", "External links\n", "\n", " * [Gamma distribution on Wikipedia](http://en.wikipedia.org/wiki/Gamma_distribution)\n" ], "text/plain": [ "\u001b[36m Gamma(α,θ)\u001b[39m\n", "\n", " The \u001b[4mGamma distribution\u001b[24m with shape parameter \u001b[36mα\u001b[39m and scale \u001b[36mθ\u001b[39m has probability\n", " density function\n", "\n", "\u001b[35mf(x; \\alpha, \\theta) = \\frac{x^{\\alpha-1} e^{-x/\\theta}}{\\Gamma(\\alpha) \\theta^\\alpha},\u001b[39m\n", "\u001b[35m\\quad x > 0\u001b[39m\n", "\n", "\u001b[36m Gamma() # Gamma distribution with unit shape and unit scale, i.e. Gamma(1, 1)\u001b[39m\n", "\u001b[36m Gamma(α) # Gamma distribution with shape α and unit scale, i.e. Gamma(α, 1)\u001b[39m\n", "\u001b[36m Gamma(α, θ) # Gamma distribution with shape α and scale θ\u001b[39m\n", "\u001b[36m \u001b[39m\n", "\u001b[36m params(d) # Get the parameters, i.e. (α, θ)\u001b[39m\n", "\u001b[36m shape(d) # Get the shape parameter, i.e. α\u001b[39m\n", "\u001b[36m scale(d) # Get the scale parameter, i.e. θ\u001b[39m\n", "\n", " External links\n", "\n", " • Gamma distribution on Wikipedia\n", " (http://en.wikipedia.org/wiki/Gamma_distribution)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "?Gamma" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "以下のようにして作った mvnormal は確率分布のオブジェクトだと思える. Julia では obj.method(x) とは書かずに, method(obj, x) のように書くと思ってよい." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "FullNormal(\n", "dim: 2\n", "μ: [1.0, 2.0]\n", "Σ: [1.0 -1.0; -1.0 5.0]\n", ")\n" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "μ = [1.0, 2.0]\n", "Σ = Float64[\n", " 1 -1\n", " -1 5\n", "]\n", "mvnormal = MvNormal(μ, Σ)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "確率分布 mvnormal に従う擬似乱数の生成は次の通り. (0~1区間の一様分布の乱数や標準正規分布に従う乱数はそれぞれ `rand()`, `randn()` で生成できる(Distributions.jlは必要ない).)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "-2\n", "\n", "\n", "-1\n", "\n", "\n", "0\n", "\n", "\n", "1\n", "\n", "\n", "2\n", "\n", "\n", "3\n", "\n", "\n", "4\n", "\n", "\n", "-2.5\n", "\n", "\n", "0.0\n", "\n", "\n", "2.5\n", "\n", "\n", "5.0\n", "\n", "\n", "7.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "-2\n", "\n", "\n", "-1\n", "\n", "\n", "0\n", "\n", "\n", "1\n", "\n", "\n", "2\n", "\n", "\n", "3\n", "\n", "\n", "4\n", "\n", "\n", "-2.5\n", "\n", "\n", "0.0\n", "\n", "\n", "2.5\n", "\n", "\n", "5.0\n", "\n", "\n", "7.5\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "-2\n", "\n", "\n", "-1\n", "\n", "\n", "0\n", "\n", "\n", "1\n", "\n", "\n", "2\n", "\n", "\n", "3\n", "\n", "\n", "4\n", "\n", "\n", "-2.5\n", "\n", "\n", "0.0\n", "\n", "\n", "2.5\n", "\n", "\n", "5.0\n", "\n", "\n", "7.5\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Plots\n", "using KernelDensity\n", "\n", "n = 1000 # サンプルサイズ\n", "X = rand(mvnormal, n) # 確率分布 mvnormal に従って乱数を生成\n", "ik = InterpKDE(kde((X[1,:], X[2,:])))\n", "pdfik(x,y) = pdf(ik,x,y)\n", "c = pdfik.(X[1,:], X[2,:])\n", "\n", "pdfmvn(x,y) = pdf(mvnormal, [x,y]) # 確率分布 mvnormal の確率密度函数\n", "xmin, xmax = minimum(X[1,:]), maximum(X[1,:])\n", "ymin, ymax = minimum(X[2,:]), maximum(X[2,:])\n", "x = range(xmin, xmax, length=200)\n", "y = range(ymin, ymax, length=200)\n", "z = pdfmvn.(x', y)\n", "\n", "gr(legend=false)\n", "P1 = plot(background_color_inside=\"gray\", color=:thermal)\n", "plot!(xlim=(xmin,xmax), ylim=(ymin,ymax))\n", "scatter!(X[1,:], X[2,:], zcolor=c, markersize=2, markerstrokewidth=0)\n", "P2 = heatmap(x, y, z, color=:thermal)\n", "P3 = contour(x, y, z, color=:thermal)\n", "plot(P1, P2, P3, size=(700, 200), layout=@layout([a b c]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "複数のグラフを1つにまとめるときのレイアウトについては [Layouts - Plots](http://docs.juliaplots.org/latest/layouts/) を参照せよ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "以下はデータフレームを利用している." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "

7,185 rows × 8 columns

SchoolMinrtySxSSSMAchMeanSESSectorCSES
Categorical…Categorical…Categorical…Float64Float64Float64Categorical…Float64
11224NoFemale-1.5285.876-0.434383Public-1.09362
21224NoFemale-0.58819.708-0.434383Public-0.153617
31224NoMale-0.52820.349-0.434383Public-0.093617
41224NoMale-0.6688.781-0.434383Public-0.233617
51224NoMale-0.15817.898-0.434383Public0.276383
61224NoMale0.0224.583-0.434383Public0.456383
71224NoFemale-0.618-2.832-0.434383Public-0.183617
81224NoMale-0.9980.523-0.434383Public-0.563617
91224NoFemale-0.8881.527-0.434383Public-0.453617
101224NoMale-0.45821.521-0.434383Public-0.023617
" ], "text/latex": [ "\\begin{tabular}{r|cccccccc}\n", "\t& School & Minrty & Sx & SSS & MAch & MeanSES & Sector & CSES\\\\\n", "\t\\hline\n", "\t& Categorical… & Categorical… & Categorical… & Float64 & Float64 & Float64 & Categorical… & Float64\\\\\n", "\t\\hline\n", "\t1 & 1224 & No & Female & -1.528 & 5.876 & -0.434383 & Public & -1.09362 \\\\\n", "\t2 & 1224 & No & Female & -0.588 & 19.708 & -0.434383 & Public & -0.153617 \\\\\n", "\t3 & 1224 & No & Male & -0.528 & 20.349 & -0.434383 & Public & -0.093617 \\\\\n", "\t4 & 1224 & No & Male & -0.668 & 8.781 & -0.434383 & Public & -0.233617 \\\\\n", "\t5 & 1224 & No & Male & -0.158 & 17.898 & -0.434383 & Public & 0.276383 \\\\\n", "\t6 & 1224 & No & Male & 0.022 & 4.583 & -0.434383 & Public & 0.456383 \\\\\n", "\t7 & 1224 & No & Female & -0.618 & -2.832 & -0.434383 & Public & -0.183617 \\\\\n", "\t8 & 1224 & No & Male & -0.998 & 0.523 & -0.434383 & Public & -0.563617 \\\\\n", "\t9 & 1224 & No & Female & -0.888 & 1.527 & -0.434383 & Public & -0.453617 \\\\\n", "\t10 & 1224 & No & Male & -0.458 & 21.521 & -0.434383 & Public & -0.023617 \\\\\n", "\t$\\dots$ & $\\dots$ & $\\dots$ & $\\dots$ & $\\dots$ & $\\dots$ & $\\dots$ & $\\dots$ & $\\dots$ \\\\\n", "\\end{tabular}\n" ], "text/plain": [ "7185×8 DataFrame\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using RDatasets\n", "using StatsPlots: @df\n", "school = RDatasets.dataset(\"mlmRev\",\"Hsb82\")\n", "ENV[\"LINES\"] = 10 # 表示する最大行数を指定\n", "display(school)\n", "ENV[\"LINES\"] = 100;" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "\n", "\n", "10\n", "\n", "\n", "20\n", "\n", "\n", "30\n", "\n", "\n", "0.00\n", "\n", "\n", "0.01\n", "\n", "\n", "0.02\n", "\n", "\n", "0.03\n", "\n", "\n", "0.04\n", "\n", "\n", "0.05\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Male\n", "\n", "\n", "\n", "Female\n", "\n", "\n" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gr(size=(500, 250))\n", "@df school density(:MAch, group=:Sx, legend=:topleft)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0\n", "\n", "\n", "10\n", "\n", "\n", "20\n", "\n", "\n", "30\n", "\n", "\n", "0.00\n", "\n", "\n", "0.01\n", "\n", "\n", "0.02\n", "\n", "\n", "0.03\n", "\n", "\n", "0.04\n", "\n", "\n", "0.05\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Male Public\n", "\n", "\n", "\n", "Male Catholic\n", "\n", "\n", "\n", "Female Public\n", "\n", "\n", "\n", "Female Catholic\n", "\n", "\n" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gr(size=(640, 320))\n", "@df school density(:MAch, group=(:Sx, :Sector), legend=:topleft, legendfontsize=7)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "\\begin{verbatim}\n", "`@df d x`\n", "\\end{verbatim}\n", "Convert every symbol in the expression \\texttt{x} with the respective column in \\texttt{d} if it exists.\n", "\n", "If you want to avoid replacing the symbol, escape it with \\texttt{\\^{}}.\n", "\n", "\\texttt{NA} values are replaced with \\texttt{NaN} for columns of \\texttt{Float64} and \\texttt{\"\"} or \\texttt{Symbol()} for strings and symbols respectively.\n", "\n", "\\texttt{x} can be either a plot command or a block of plot commands.\n", "\n", "\\rule{\\textwidth}{1pt}\n", "\\begin{verbatim}\n", "`@df x`\n", "\\end{verbatim}\n", "Curried version of \\texttt{@df d x}. Outputs an anonymous function \\texttt{d -> @df d x}.\n", "\n" ], "text/markdown": [ "```\n", "`@df d x`\n", "```\n", "\n", "Convert every symbol in the expression `x` with the respective column in `d` if it exists.\n", "\n", "If you want to avoid replacing the symbol, escape it with `^`.\n", "\n", "`NA` values are replaced with `NaN` for columns of `Float64` and `\"\"` or `Symbol()` for strings and symbols respectively.\n", "\n", "`x` can be either a plot command or a block of plot commands.\n", "\n", "---\n", "\n", "```\n", "`@df x`\n", "```\n", "\n", "Curried version of `@df d x`. Outputs an anonymous function `d -> @df d x`.\n" ], "text/plain": [ "\u001b[36m `@df d x`\u001b[39m\n", "\n", " Convert every symbol in the expression \u001b[36mx\u001b[39m with the respective column in \u001b[36md\u001b[39m if\n", " it exists.\n", "\n", " If you want to avoid replacing the symbol, escape it with \u001b[36m^\u001b[39m.\n", "\n", " \u001b[36mNA\u001b[39m values are replaced with \u001b[36mNaN\u001b[39m for columns of \u001b[36mFloat64\u001b[39m and \u001b[36m\"\"\u001b[39m or \u001b[36mSymbol()\u001b[39m\n", " for strings and symbols respectively.\n", "\n", " \u001b[36mx\u001b[39m can be either a plot command or a block of plot commands.\n", "\n", " ────────────────────────────────────────────────────────────────────────────\n", "\n", "\u001b[36m `@df x`\u001b[39m\n", "\n", " Curried version of \u001b[36m@df d x\u001b[39m. Outputs an anonymous function \u001b[36md -> @df d x\u001b[39m." ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "?@df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Nemo.jl と Hecke.jl で代数計算\n", "\n", "Nemo.jl と Hecke.jl の詳細については以下のウェブサイトを参照せよ.\n", "\n", "* Nemo.jl\n", " * [Nemo.jlのウェブサイト](http://nemocas.org) → [Benchmarks](http://nemocas.org/benchmarks.html) (Nemo.jlは高速である)\n", " * [Nemo.jlのリポジトリ](https://github.com/Nemocas/Nemo.jl)\n", " * [Nemo.jlのドキュメント](http://nemocas.github.io/Nemo.jl/latest/)\n", "* Hecke.jl\n", " * [Hecke.jlのリポジトリ](https://github.com/thofma/Hecke.jl)\n", " * [Hecke.jlのドキュメント](http://thofma.github.io/Hecke.jl/latest/)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Project.toml`\n", "\u001b[90m [no changes]\u001b[39m\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Manifest.toml`\n", "\u001b[90m [no changes]\u001b[39m\n" ] } ], "source": [ "]add Nemo" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Project.toml`\n", "\u001b[90m [no changes]\u001b[39m\n", "\u001b[32m\u001b[1m Updating\u001b[22m\u001b[39m `C:\\Users\\genkuroki\\.julia\\environments\\v1.1\\Manifest.toml`\n", "\u001b[90m [no changes]\u001b[39m\n" ] } ], "source": [ "]add Hecke" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Welcome to Nemo version 0.13.2\n", "\n", "Nemo comes with absolutely no warranty whatsoever\n", "\n" ] } ], "source": [ "using Nemo" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "┌ Info: Recompiling stale cache file C:\\Users\\genkuroki\\.julia\\compiled\\v1.1\\Hecke\\lhBAK.ji for Hecke [3e1990a7-5d81-5526-99ce-9ba3ff248f21]\n", "└ @ Base loading.jl:1184\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Welcome to Nemo version 0.13.2\n", "\n", "Nemo comes with absolutely no warranty whatsoever\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING: Method definition invert_rows(Nemo.fmpz_mat) in module Nemo at C:\\Users\\genkuroki\\.julia\\packages\\Nemo\\lv3u5\\src\\flint\\fmpz_mat.jl:287 overwritten in module Hecke at C:\\Users\\genkuroki\\.julia\\packages\\Hecke\\udlBN\\src\\Misc\\Matrix.jl:315.\n", "WARNING: Method definition invert_cols(Nemo.fmpz_mat) in module Nemo at C:\\Users\\genkuroki\\.julia\\packages\\Nemo\\lv3u5\\src\\flint\\fmpz_mat.jl:295 overwritten in module Hecke at C:\\Users\\genkuroki\\.julia\\packages\\Hecke\\udlBN\\src\\Misc\\Matrix.jl:327.\n", "WARNING: Method definition invert_rows!(Nemo.fmpz_mat) in module Nemo at C:\\Users\\genkuroki\\.julia\\packages\\Nemo\\lv3u5\\src\\flint\\fmpz_mat.jl:282 overwritten in module Hecke at C:\\Users\\genkuroki\\.julia\\packages\\Hecke\\udlBN\\src\\Misc\\Matrix.jl:339.\n", "WARNING: Method definition invert_cols!(Nemo.fmpz_mat) in module Nemo at C:\\Users\\genkuroki\\.julia\\packages\\Nemo\\lv3u5\\src\\flint\\fmpz_mat.jl:290 overwritten in module Hecke at C:\\Users\\genkuroki\\.julia\\packages\\Hecke\\udlBN\\src\\Misc\\Matrix.jl:461.\n" ] }, { "data": { "text/html": [ "$\\require{action}$" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "Welcome to \n", "\n", "\u001b[31m _ _ _ \u001b[39m\n", "\u001b[31m | | | | | | \u001b[39m\n", "\u001b[31m | |__| | ___ ___| | _____ \u001b[39m\n", "\u001b[31m | __ |/ _ \\/ __| |/ / _ \\\u001b[39m\n", "\u001b[31m | | | | __/ (__| < __/\u001b[39m\n", "\u001b[31m |_| |_|\\___|\\___|_|\\_\\___|\u001b[39m\n", "\u001b[31m \u001b[39m\n", "Version\u001b[32m 0.6.1 \u001b[39m... \n", " ... which comes with absolutely no warranty whatsoever\n", "(c) 2015-2019 by Claus Fieker, Tommy Hofmann and Carlo Sircana\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING: using Hecke.density in module Main conflicts with an existing identifier.\n" ] } ], "source": [ "using Hecke" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Bernoulli多項式を母函数の展開で計算" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "scrolled": false }, "outputs": [ { "data": { "text/html": [ "$[1, x-1//2, x^{2}-x+1//6, x^{3}-3//2x^{2}+1//2x, x^{4}-2x^{3}+x^{2}-1//30, x^{5}-5//2x^{4}+5//3x^{3}-1//6x, x^{6}-3x^{5}+5//2x^{4}-1//2x^{2}+1//42]$" ], "text/plain": [ "7-element Array{fmpq_poly,1}:\n", " 1 \n", " x-1//2 \n", " x^2-x+1//6 \n", " x^3-3//2*x^2+1//2*x \n", " x^4-2*x^3+x^2-1//30 \n", " x^5-5//2*x^4+5//3*x^3-1//6*x \n", " x^6-3*x^5+5//2*x^4-1//2*x^2+1//42" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n = 6\n", "R, x = FlintQQ[\"x\"]\n", "S, z = PowerSeriesRing(R, n+2, \"z\")\n", "Z = z + O(z^(n+2))\n", "Bernoulli_Gen = divexact(Z*exp(x*Z), exp(Z)-1)\n", "Bernoulli_Nemo = @. factorial(BigInt[0:n;]) * coeff(Bernoulli_Gen, 0:n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nemoの式を文字列に変換" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$[\"1\", \"x-1//2\", \"x^2-x+1//6\", \"x^3-3//2*x^2+1//2*x\", \"x^4-2*x^3+x^2-1//30\", \"x^5-5//2*x^4+5//3*x^3-1//6*x\", \"x^6-3*x^5+5//2*x^4-1//2*x^2+1//42\"]$" ], "text/plain": [ "7-element Array{String,1}:\n", " \"1\" \n", " \"x-1//2\" \n", " \"x^2-x+1//6\" \n", " \"x^3-3//2*x^2+1//2*x\" \n", " \"x^4-2*x^3+x^2-1//30\" \n", " \"x^5-5//2*x^4+5//3*x^3-1//6*x\" \n", " \"x^6-3*x^5+5//2*x^4-1//2*x^2+1//42\"" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Bernoulli_Str = (x->\"$x\").(Bernoulli_Nemo)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "文字列をJuliaのExprに変換" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$[1, :(x - 1 // 2), :((x ^ 2 - x) + 1 // 6), :((x ^ 3 - 3 // 2 * x ^ 2) + 1 // 2 * x), :(((x ^ 4 - 2 * x ^ 3) + x ^ 2) - 1 // 30), :(((x ^ 5 - 5 // 2 * x ^ 4) + 5 // 3 * x ^ 3) - 1 // 6 * x), :((((x ^ 6 - 3 * x ^ 5) + 5 // 2 * x ^ 4) - 1 // 2 * x ^ 2) + 1 // 42)]$" ], "text/plain": [ "7-element Array{Any,1}:\n", " 1 \n", " :(x - 1 // 2) \n", " :((x ^ 2 - x) + 1 // 6) \n", " :((x ^ 3 - 3 // 2 * x ^ 2) + 1 // 2 * x) \n", " :(((x ^ 4 - 2 * x ^ 3) + x ^ 2) - 1 // 30) \n", " :(((x ^ 5 - 5 // 2 * x ^ 4) + 5 // 3 * x ^ 3) - 1 // 6 * x) \n", " :((((x ^ 6 - 3 * x ^ 5) + 5 // 2 * x ^ 4) - 1 // 2 * x ^ 2) + 1 // 42)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Bernoulli_Expr = Meta.parse.(Bernoulli_Str)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "JuliaのExprをSymPyの式に変換し, 整形して表示" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "$$B_{0}(x) = 1$$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$$B_{1}(x) = x - \\frac{1}{2}$$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$$B_{2}(x) = x^{2} - x + \\frac{1}{6}$$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$$B_{3}(x) = x^{3} - \\frac{3 x^{2}}{2} + \\frac{x}{2}$$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$$B_{4}(x) = x^{4} - 2 x^{3} + x^{2} - \\frac{1}{30}$$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$$B_{5}(x) = x^{5} - \\frac{5 x^{4}}{2} + \\frac{5 x^{3}}{3} - \\frac{x}{6}$$" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "$$B_{6}(x) = x^{6} - 3 x^{5} + \\frac{5 x^{4}}{2} - \\frac{x^{2}}{2} + \\frac{1}{42}$$" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using SymPy: SymPy, sympy, Sym, @vars, PI, oo\n", "@vars x\n", "Bernoulli_Sym = eval.(Bernoulli_Expr)\n", "for k in 0:lastindex(Bernoulli_Sym)-1\n", " display(\"text/html\", \n", " raw\"$$\" *\n", " \"B_{$k}(x) = \" *\n", " sympy.latex(Bernoulli_Sym[k+1]) *\n", " raw\"$$\"\n", " )\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 類体論\n", "\n", "[Conversions - Class Field Theory - Hecke](http://thofma.github.io/Hecke.jl/latest/class_fields/intro.html#Conversions-1) より. \n", "\n", "class_group の計算は結構重い計算になる." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/html": [ "($Qx$, $x$)" ], "text/plain": [ "(Univariate Polynomial Ring in x over Rational Field, x)" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Qx, x = PolynomialRing(FlintQQ, \"x\")" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/html": [ "($K$, $a$)" ], "text/plain": [ "(Number field over Rational Field with defining polynomial x^2-10, a)" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "K, a = NumberField(x^2 - 10, \"a\")" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 77.897933 seconds (99.12 M allocations: 5.050 GiB, 7.15% gc time)\n" ] }, { "data": { "text/html": [ "($c$, $mc: c\\to\\text{Set of ideals of }\\mathcal O_K$)" ], "text/plain": [ "(GrpAb: Z/2, ClassGroup map of Set of ideals of Maximal order of Number field over Rational Field with defining polynomial x^2-10 \n", "with basis nf_elem[1, a]\n", "\n", ")" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@time c, mc = class_group(K)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.059833 seconds (43.04 k allocations: 2.218 MiB)\n" ] }, { "data": { "text/plain": [ "Class field defined mod (<1, 1>, InfPlc[]) of structure Abelian group with structure: Z/2" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@time A = ray_class_field(mc)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 22.216436 seconds (24.26 M allocations: 1.158 GiB, 6.03% gc time)\n" ] }, { "data": { "text/plain": [ "non-simple Relative number field over\n", "Number field over Rational Field with defining polynomial x^2-10\n", " with defining polynomials AbstractAlgebra.Generic.MPoly{nf_elem}[_$1^2+(-2)]" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@time K = number_field(A)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 10.009856 seconds (13.49 M allocations: 677.174 MiB, 7.65% gc time)\n" ] }, { "data": { "text/plain": [ "Relative maximal order of non-simple Relative number field over\n", "Number field over Rational Field with defining polynomial x^2-10\n", " with defining polynomials AbstractAlgebra.Generic.MPoly{nf_elem}[_$1^2+(-2)]\n", "with pseudo-basis \n", "(1, 1//1 * <1, a+1>)\n", "(_$1+(a), 1//4 * <2, 3*a+2>)" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@time ZK = maximal_order(K)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0.005820 seconds (2.71 k allocations: 163.219 KiB)\n" ] }, { "data": { "text/html": [ "true" ], "text/plain": [ "true" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@time isone(discriminant(ZK))" ] } ], "metadata": { "_draft": { "nbviewer_url": "https://gist.github.com/5ae6933c4a55a77530f870bc84a85fbd" }, "gist": { "data": { "description": "msfd28/install.ipynb", "public": true }, "id": "5ae6933c4a55a77530f870bc84a85fbd" }, "kernelspec": { "display_name": "Julia 1.1.0", "language": "julia", "name": "julia-1.1" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.1.0" }, "toc": { "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "目次", "title_sidebar": "目次", "toc_cell": true, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }