From 6559e3252a56a032a081498d1362bdc47e66a7fd Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 15:50:14 +0100 Subject: [PATCH 1/9] rename everything --- LICENSE.md | 4 ++-- README.md | 12 +++++----- docs/make.jl | 6 ++--- docs/src/api.md | 41 ++--------------------------------- src/ruleset_loading.jl | 1 + test/demos/reversediffzero.jl | 1 + test/ruleset_loading.jl | 4 ++-- 7 files changed, 17 insertions(+), 52 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index d8cddc9..956cad7 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ -The ChainRulesCore.jl package is licensed under the MIT "Expat" License: +The ChainRulesOverloadGeneration.jl package is licensed under the MIT "Expat" License: > Copyright (c) 2018-2019: Jarrett Revels, and other JuliaDiff Contributors: -> https://github.com/JuliaDiff/ChainRulesCore.jl/contributors +> https://github.com/JuliaDiff/ChainRulesOverloadGeneration.jl/contributors > > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 79b3cdc..5ad6f8c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ -# ChainRulesCore +# ChainRulesOverloadGeneration -[![Build Status](https://github.com/JuliaDiff/ChainRulesCore.jl/workflows/CI/badge.svg)](https://github.com/JuliaDiff/ChainRulesCore.jl/actions?query=workflow:CI) -[![Coverage](https://codecov.io/gh/JuliaDiff/ChainRulesCore.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaDiff/ChainRulesCore.jl) +[![Build Status](https://github.com/JuliaDiff/ChainRulesOverloadGeneration.jl/workflows/CI/badge.svg)](https://github.com/JuliaDiff/ChainRulesOverloadGeneration.jl/actions?query=workflow:CI) +[![Coverage](https://codecov.io/gh/JuliaDiff/ChainRulesOverloadGeneration.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaDiff/ChainRulesOverloadGeneration.jl) [![Code Style: Blue](https://img.shields.io/badge/code%20style-blue-4495d1.svg)](https://github.com/invenia/BlueStyle) [![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor's%20Guide-blueviolet)](https://github.com/SciML/ColPrac) [![DOI](https://zenodo.org/badge/199721843.svg)](https://zenodo.org/badge/latestdoi/199721843) **Docs:** -[![](https://img.shields.io/badge/docs-master-blue.svg)](https://juliadiff.org/ChainRulesCore.jl/dev) -[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadiff.org/ChainRulesCore.jl/stable) +[![](https://img.shields.io/badge/docs-master-blue.svg)](https://juliadiff.org/ChainRulesOverloadGeneration.jl/dev) +[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadiff.org/ChainRulesOverloadGeneration.jl/stable) -The ChainRulesCore package provides a light-weight dependency for defining sensitivities for functions in your packages, without you needing to depend on ChainRules itself. +The ChainRulesOverloadGeneration package provides a light-weight dependency for defining sensitivities for functions in your packages, without you needing to depend on ChainRules itself. This will allow your package to be used with [ChainRules.jl](https://github.com/JuliaDiff/ChainRules.jl), which aims to provide a variety of common utilities that can be used by downstream automatic differentiation (AD) tools to define and execute forward-, reverse-, and mixed-mode primitives. diff --git a/docs/make.jl b/docs/make.jl index 0115025..fd7f304 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -19,10 +19,10 @@ DocMeta.setdocmeta!( end ) -indigo = DocThemeIndigo.install(ChainRulesCore) +indigo = DocThemeIndigo.install(ChainRulesOverloadGeneration) makedocs( - modules=[ChainRulesCore], + modules=[ChainRulesOverloadGeneration], format=Documenter.HTML( prettyurls=false, assets=[indigo], @@ -67,6 +67,6 @@ makedocs( ) deploydocs( - repo = "github.com/JuliaDiff/ChainRulesCore.jl.git", + repo = "github.com/JuliaDiff/ChainRulesOverloadGeneration.jl.git", push_preview=true, ) diff --git a/docs/src/api.md b/docs/src/api.md index d6db494..0b24ebb 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -1,49 +1,12 @@ # API Documentation -## Rules ```@autodocs -Modules = [ChainRulesCore] -Pages = ["rules.jl"] -Private = false -``` - -## Rule Definition Tools -```@autodocs -Modules = [ChainRulesCore] +Modules = [ChainRulesOverloadGeneration] Pages = ["rule_definition_tools.jl"] Private = false ``` -## Differentials -```@autodocs -Modules = [ChainRulesCore] -Pages = [ - "differentials/abstract_zero.jl", - "differentials/one.jl", - "differentials/composite.jl", - "differentials/thunks.jl", - "differentials/abstract_differential.jl", - "differentials/notimplemented.jl", -] -Private = false -``` - -## Accumulation -```@docs -add!! -ChainRulesCore.is_inplaceable_destination -``` - -## Ruleset Loading -```@autodocs -Modules = [ChainRulesCore] -Pages = ["ruleset_loading.jl"] -Private = false -``` - ## Internal ```@docs -ChainRulesCore.AbstractTangent -ChainRulesCore.debug_mode -ChainRulesCore.clear_new_rule_hooks! +ChainRulesOverloadGeneration.clear_new_rule_hooks! ``` diff --git a/src/ruleset_loading.jl b/src/ruleset_loading.jl index aa40fae..5180e03 100644 --- a/src/ruleset_loading.jl +++ b/src/ruleset_loading.jl @@ -60,6 +60,7 @@ Excluding the fallback rule that returns `nothing` for every input. """ function _rule_list end # The fallback rules are the only rules defined in ChainRulesCore & that is how we skip them +# TODO this needs to be changed to work now it is in it's own repo _rule_list(rule_kind) = (m for m in methods(rule_kind) if m.module != @__MODULE__) diff --git a/test/demos/reversediffzero.jl b/test/demos/reversediffzero.jl index 540b8ea..dbb3bc5 100644 --- a/test/demos/reversediffzero.jl +++ b/test/demos/reversediffzero.jl @@ -1,6 +1,7 @@ "The simplest viable reverse mode a AD, only supports `Float64`" module ReverseDiffZero using ChainRulesCore +using ChainRulesOverloadGeneration using Test ######################################### diff --git a/test/ruleset_loading.jl b/test/ruleset_loading.jl index e1743f0..5e24161 100644 --- a/test/ruleset_loading.jl +++ b/test/ruleset_loading.jl @@ -10,7 +10,7 @@ op = sig.parameters[1] push!(rrule_history, op) end - + @testset "new rules hit the hooks" begin # Now define some rules @scalar_rule x + y (1, 1) @@ -38,7 +38,7 @@ end @testset "_primal_sig" begin - _primal_sig = ChainRulesCore._primal_sig + _primal_sig = ChainRulesOverloadGeneration._primal_sig @testset "frule" begin @test isequal( # DataType without shared type but with constraint _primal_sig(frule, Tuple{typeof(frule), Any, typeof(*), Int, Vector{Int}}), From 00d12d13bfd97462bddd44efe17ed5a075ba23bf Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 16:08:13 +0100 Subject: [PATCH 2/9] Basic files created --- .github/workflows/IntegrationTest.yml | 10 ++-------- Project.toml | 15 +++++++++++++++ README.md | 7 ++----- docs/Manifest.toml | 12 +++++++++--- docs/Project.toml | 1 + docs/make.jl | 2 +- src/ChainRulesOverloadGeneration.jl | 13 +++++++++++++ src/ruleset_loading.jl | 4 ---- test/demos/forwarddiffzero.jl | 1 + test/runtests.jl | 14 ++++++++++++++ 10 files changed, 58 insertions(+), 21 deletions(-) create mode 100644 Project.toml create mode 100644 src/ChainRulesOverloadGeneration.jl create mode 100644 test/runtests.jl diff --git a/.github/workflows/IntegrationTest.yml b/.github/workflows/IntegrationTest.yml index 8cf6bb1..139a131 100644 --- a/.github/workflows/IntegrationTest.yml +++ b/.github/workflows/IntegrationTest.yml @@ -15,13 +15,7 @@ jobs: julia-version: [1.5] os: [ubuntu-latest] package: - - {user: JuliaDiff, repo: ChainRules.jl} - - {user: JuliaMath, repo: SpecialFunctions.jl} - - {user: invenia, repo: BlockDiagonals.jl} - - {user: invenia, repo: PDMatsExtras.jl} - - {user: chrisbrahms, repo: Hankel.jl} - - {user: SciML, repo: DiffEqBase.jl} - - {user: dfdx, repo: Yota.jl} + # - {user: Invenia, repo: Nabla.jl} steps: - uses: actions/checkout@v2 @@ -43,7 +37,7 @@ jobs: # force it to use this PR's version of the package Pkg.develop(PackageSpec(path=".")) # resolver may fail with main deps Pkg.update() - Pkg.test() # resolver may fail with test time deps + Pkg.test() # resolver may fail with test time deps catch err err isa Pkg.Resolve.ResolverError || rethrow() # If we can't resolve that means this is incompatible by SemVer and this is fine diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..ed060f4 --- /dev/null +++ b/Project.toml @@ -0,0 +1,15 @@ +name = "ChainRulesOverloadGeneration" +uuid = "f51149dc-2911-5acf-81fc-2076a2a81d4f" +version = "0.1.0" + +[deps] +ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + +[compat] +ChainRulesCore = "0.9" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/README.md b/README.md index 5ad6f8c..241a40e 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,5 @@ [![](https://img.shields.io/badge/docs-master-blue.svg)](https://juliadiff.org/ChainRulesOverloadGeneration.jl/dev) [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadiff.org/ChainRulesOverloadGeneration.jl/stable) -The ChainRulesOverloadGeneration package provides a light-weight dependency for defining sensitivities for functions in your packages, without you needing to depend on ChainRules itself. - -This will allow your package to be used with [ChainRules.jl](https://github.com/JuliaDiff/ChainRules.jl), which aims to provide a variety of common utilities that can be used by downstream automatic differentiation (AD) tools to define and execute forward-, reverse-, and mixed-mode primitives. - -This package is a work in progress; PRs welcome! +The ChainRulesOverloadGeneration package provides a suite of methods for using [ChainRulesCore.jl](https://github.com/JuliaDiff/ChainRulesCore.jl) rules in operator overloaded based AD systems. +It tracks what rules are defined at any point in time, and lets you trigger functions to which can use `@eval` in order to define the matching operator overloads. diff --git a/docs/Manifest.toml b/docs/Manifest.toml index d0f0169..3b5c092 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -11,15 +11,21 @@ uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" [[ChainRulesCore]] deps = ["Compat", "LinearAlgebra", "SparseArrays"] -path = ".." +git-tree-sha1 = "b391f22252b8754f4440de1f37ece49d8a7314bb" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" version = "0.9.44" +[[ChainRulesOverloadGeneration]] +deps = ["ChainRulesCore"] +path = ".." +uuid = "f51149dc-2911-5acf-81fc-2076a2a81d4f" +version = "0.1.0" + [[Compat]] deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "0900bc19193b8e672d9cd477e6cd92d9e7c02f99" +git-tree-sha1 = "e4e2b39db08f967cc1360951f01e8a75ec441cab" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.29.0" +version = "3.30.0" [[Dates]] deps = ["Printf"] diff --git a/docs/Project.toml b/docs/Project.toml index cab507d..f3eff3a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,6 @@ [deps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +ChainRulesOverloadGeneration = "f51149dc-2911-5acf-81fc-2076a2a81d4f" Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" DocThemeIndigo = "8bac0ac5-51bf-41f9-885e-2bf1ac2bec5f" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" diff --git a/docs/make.jl b/docs/make.jl index fd7f304..dabc533 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -4,7 +4,7 @@ using DocThemeIndigo using Markdown DocMeta.setdocmeta!( - ChainRulesCore, + ChainRulesOverloadGeneration, :DocTestSetup, quote using Random diff --git a/src/ChainRulesOverloadGeneration.jl b/src/ChainRulesOverloadGeneration.jl new file mode 100644 index 0000000..bd6676b --- /dev/null +++ b/src/ChainRulesOverloadGeneration.jl @@ -0,0 +1,13 @@ +using ChainRulesCore + +export on_new_rule, refresh_rules + +include("precompile.jl") +include("ruleset_loading.jl") + +function __init__() + # Need to refresh rules when a package is loaded + push!(Base.package_callbacks, _package_hook) +end + +end diff --git a/src/ruleset_loading.jl b/src/ruleset_loading.jl index 5180e03..37da02e 100644 --- a/src/ruleset_loading.jl +++ b/src/ruleset_loading.jl @@ -1,9 +1,5 @@ # Infastructure to support generating overloads from rules. _package_hook(::Base.PkgId) = refresh_rules() -function __init__() - # Need to refresh rules when a package is loaded - push!(Base.package_callbacks, _package_hook) -end # Holds all the hook functions that are invokes when a new rule is defined const RRULE_DEFINITION_HOOKS = Function[] diff --git a/test/demos/forwarddiffzero.jl b/test/demos/forwarddiffzero.jl index 13a1b19..e75ffc1 100644 --- a/test/demos/forwarddiffzero.jl +++ b/test/demos/forwarddiffzero.jl @@ -1,6 +1,7 @@ "The simplest viable forward mode a AD, only supports `Float64`" module ForwardDiffZero using ChainRulesCore +using ChainRulesOverloadGeneration using Test ######################################### diff --git a/test/runtests.jl b/test/runtests.jl new file mode 100644 index 0000000..be4f3df --- /dev/null +++ b/test/runtests.jl @@ -0,0 +1,14 @@ +using Base.Broadcast: broadcastable +using BenchmarkTools +using ChainRulesCore +using ChainRulesOverloadGeneration +using Test + +@testset "ChainRulesCore" begin + include("ruleset_loading.jl") + + @testset "demos" begin + include("demos/forwarddiffzero.jl") + include("demos/reversediffzero.jl") + end +end From 08f7bf757019d5c1b4f61af0ca06138643f1097d Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 17:57:22 +0100 Subject: [PATCH 3/9] Make tests pass --- test/runtests.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index be4f3df..8ddd53f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,7 +1,9 @@ -using Base.Broadcast: broadcastable -using BenchmarkTools using ChainRulesCore using ChainRulesOverloadGeneration +# resolve conflicts while this code exists in both. +const on_new_rule = ChainRulesOverloadGeneration.on_new_rule +const refresh_rules = ChainRulesOverloadGeneration.refresh_rules + using Test @testset "ChainRulesCore" begin From 874da9f8bc94adf7edce428b5fd94412bafe1f44 Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 17:58:09 +0100 Subject: [PATCH 4/9] make tests pass --- src/ChainRulesOverloadGeneration.jl | 6 ++++-- src/ruleset_loading.jl | 6 +++--- test/demos/forwarddiffzero.jl | 4 ++++ test/demos/reversediffzero.jl | 4 ++++ test/ruleset_loading.jl | 12 +++++++++--- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/ChainRulesOverloadGeneration.jl b/src/ChainRulesOverloadGeneration.jl index bd6676b..8804f6b 100644 --- a/src/ChainRulesOverloadGeneration.jl +++ b/src/ChainRulesOverloadGeneration.jl @@ -1,13 +1,15 @@ +module ChainRulesOverloadGeneration + using ChainRulesCore export on_new_rule, refresh_rules -include("precompile.jl") include("ruleset_loading.jl") +include("precompile.jl") function __init__() # Need to refresh rules when a package is loaded push!(Base.package_callbacks, _package_hook) end -end +end # module diff --git a/src/ruleset_loading.jl b/src/ruleset_loading.jl index 37da02e..876b8b8 100644 --- a/src/ruleset_loading.jl +++ b/src/ruleset_loading.jl @@ -55,10 +55,10 @@ Returns a list of all the methods of the currently defined rules of the given ki Excluding the fallback rule that returns `nothing` for every input. """ function _rule_list end -# The fallback rules are the only rules defined in ChainRulesCore & that is how we skip them -# TODO this needs to be changed to work now it is in it's own repo -_rule_list(rule_kind) = (m for m in methods(rule_kind) if m.module != @__MODULE__) +_rule_list(rule_kind) = (m for m in methods(rule_kind) if !_is_fallback(rule_kind, m)) +"check if this is the fallback-frule/rrule that always returns `nothing`" +_is_fallback(rule_kind, m::Method) = m.sig === Tuple{typeof(rule_kind), Any, Vararg{Any}} const LAST_REFRESH_RRULE = Ref(0) const LAST_REFRESH_FRULE = Ref(0) diff --git a/test/demos/forwarddiffzero.jl b/test/demos/forwarddiffzero.jl index e75ffc1..3283dd3 100644 --- a/test/demos/forwarddiffzero.jl +++ b/test/demos/forwarddiffzero.jl @@ -2,6 +2,10 @@ module ForwardDiffZero using ChainRulesCore using ChainRulesOverloadGeneration +# resolve conflicts while this code exists in both. +const on_new_rule = ChainRulesOverloadGeneration.on_new_rule +const refresh_rules = ChainRulesOverloadGeneration.refresh_rules + using Test ######################################### diff --git a/test/demos/reversediffzero.jl b/test/demos/reversediffzero.jl index dbb3bc5..d80bb99 100644 --- a/test/demos/reversediffzero.jl +++ b/test/demos/reversediffzero.jl @@ -2,6 +2,10 @@ module ReverseDiffZero using ChainRulesCore using ChainRulesOverloadGeneration +# resolve conflicts while this code exists in both. +const on_new_rule = ChainRulesOverloadGeneration.on_new_rule +const refresh_rules = ChainRulesOverloadGeneration.refresh_rules + using Test ######################################### diff --git a/test/ruleset_loading.jl b/test/ruleset_loading.jl index 5e24161..201c714 100644 --- a/test/ruleset_loading.jl +++ b/test/ruleset_loading.jl @@ -22,8 +22,8 @@ end @testset "# Make sure nothing happens anymore once we clear the hooks" begin - ChainRulesCore.clear_new_rule_hooks!(frule) - ChainRulesCore.clear_new_rule_hooks!(rrule) + ChainRulesOverloadGeneration.clear_new_rule_hooks!(frule) + ChainRulesOverloadGeneration.clear_new_rule_hooks!(rrule) old_frule_history = copy(frule_history) old_rrule_history = copy(rrule_history) @@ -34,9 +34,9 @@ @test old_rrule_history == rrule_history @test old_frule_history == frule_history end - end + @testset "_primal_sig" begin _primal_sig = ChainRulesOverloadGeneration._primal_sig @testset "frule" begin @@ -69,4 +69,10 @@ ) end end + + @testset "_is_fallback" begin + _is_fallback = ChainRulesOverloadGeneration._is_fallback + @test _is_fallback(rrule, only(methods(rrule, (Nothing,)))) + @test _is_fallback(frule, only(methods(frule, (Nothing,)))) + end end From fd6a67561b91973f814919877fca9652cb4770cb Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 18:33:29 +0100 Subject: [PATCH 5/9] make docs build --- docs/make.jl | 52 ++----------------- docs/src/api.md | 2 +- .../operator_overloading.md => index.md} | 13 +++-- 3 files changed, 14 insertions(+), 53 deletions(-) rename docs/src/{autodiff/operator_overloading.md => index.md} (80%) diff --git a/docs/make.jl b/docs/make.jl index dabc533..59754f0 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,24 +1,9 @@ -using ChainRulesCore +using ChainRulesOverloadGeneration +using ChainRulesCore: ChainRulesCore using Documenter using DocThemeIndigo using Markdown -DocMeta.setdocmeta!( - ChainRulesOverloadGeneration, - :DocTestSetup, - quote - using Random - Random.seed!(0) # frule doctest shows output - - using ChainRulesCore - # These rules are all actually defined in ChainRules.jl, but we redefine them here to - # avoid the dependency. - @scalar_rule(sin(x), cos(x)) # frule and rrule doctest - @scalar_rule(sincos(x), @setup((sinx, cosx) = Ω), cosx, -sinx) # frule doctest - @scalar_rule(hypot(x::Real, y::Real), (x / Ω, y / Ω)) # rrule doctest - end -) - indigo = DocThemeIndigo.install(ChainRulesOverloadGeneration) makedocs( @@ -26,42 +11,13 @@ makedocs( format=Documenter.HTML( prettyurls=false, assets=[indigo], - mathengine=MathJax3( - Dict( - :tex => Dict( - "inlineMath" => [["\$","\$"], ["\\(","\\)"]], - "tags" => "ams", - # TODO: remove when using physics package - "macros" => Dict( - "ip" => ["{\\left\\langle #1, #2 \\right\\rangle}", 2], - "Re" => "{\\operatorname{Re}}", - "Im" => "{\\operatorname{Im}}", - "tr" => "{\\operatorname{tr}}", - ), - ), - ), - ), ), sitename="ChainRules", - authors="Jarrett Revels and other contributors", + authors="Lyndon White and other contributors", pages=[ "Introduction" => "index.md", - "FAQ" => "FAQ.md", - "Writing Good Rules" => "writing_good_rules.md", - "Complex Numbers" => "complex.md", - "Deriving Array Rules" => "arrays.md", - "Debug Mode" => "debug_mode.md", - "Gradient Accumulation" => "gradient_accumulation.md", - "Usage in AD" => [ - "Overview" => "autodiff/overview.md", - "Operator Overloading" => "autodiff/operator_overloading.md", - ], - "Design" => [ - "Changing the Primal" => "design/changing_the_primal.md", - "Many Differential Types" => "design/many_differentials.md", - ], "API" => "api.md", - ], + ], strict=true, checkdocs=:exports, ) diff --git a/docs/src/api.md b/docs/src/api.md index 0b24ebb..e3c80e0 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -2,7 +2,7 @@ ```@autodocs Modules = [ChainRulesOverloadGeneration] -Pages = ["rule_definition_tools.jl"] +Pages = ["ruleset_loading.jl"] Private = false ``` diff --git a/docs/src/autodiff/operator_overloading.md b/docs/src/index.md similarity index 80% rename from docs/src/autodiff/operator_overloading.md rename to docs/src/index.md index 56f72e1..50bceec 100644 --- a/docs/src/autodiff/operator_overloading.md +++ b/docs/src/index.md @@ -1,4 +1,8 @@ -# Operator Overloading +# Operator Overloading AD with ChainRulesOverloadGeneration.jl + +The ChainRulesOverloadGeneration package provides a suite of methods for using [ChainRulesCore.jl](https://github.com/JuliaDiff/ChainRulesCore.jl) rules in operator overloaded based AD systems. +It tracks what rules are defined at any point in time, and lets you trigger functions to which can use `@eval` in order to define the matching operator overloads. + The principal interface for using the operator overload generation method is [`on_new_rule`](@ref). This function allows one to register a hook to be run every time a new rule is defined. @@ -14,7 +18,7 @@ or more simply you can just use conditions for this. For example if your AD only supports `AbstractMatrix{Float64}` and `Float64` inputs you might write: ```julia const ACCEPT_TYPE = Union{Float64, AbstractMatrix{Float64}} -function define_overload(sig::Type{<:Tuple{F, Vararg{ACCEPT_TYPE}}) where F +function define_overload(sig::Type{<:Tuple{F, Vararg{ACCEPT_TYPE}}}) where F @eval quote # ... end @@ -54,6 +58,7 @@ When the rules are refreshed (automatically or manually), the hooks are only tri It is useful to undo [`on_new_rule`] hook registration if you are iteratively developing your overload generation function. ## Examples +Here we define two fairly simplistic operator overloading based AD Systems to demonstrate how this is used. ### ForwardDiffZero The overload generation hook in this example is: `define_dual_overload`. @@ -62,7 +67,7 @@ The overload generation hook in this example is: `define_dual_overload`. using Markdown Markdown.parse(""" ```julia -$(read(joinpath(@__DIR__,"../../../test/demos/forwarddiffzero.jl"), String)) +$(read(joinpath(@__DIR__,"../../test/demos/forwarddiffzero.jl"), String)) ``` """) ```` @@ -74,7 +79,7 @@ The overload generation hook in this example is: `define_tracked_overload`. using Markdown Markdown.parse(""" ```julia -$(read(joinpath(@__DIR__,"../../../test/demos/reversediffzero.jl"), String)) +$(read(joinpath(@__DIR__,"../../test/demos/reversediffzero.jl"), String)) ``` """) ```` From 2866f49398cb7b7287a777e0e8c060b67aef3536 Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 19:03:01 +0100 Subject: [PATCH 6/9] break up docs --- docs/make.jl | 4 ++++ docs/src/examples/forward_mode.md | 15 +++++++++++++++ docs/src/examples/reverse_mode.md | 16 ++++++++++++++++ docs/src/index.md | 25 ------------------------- test/demos/reversediffzero.jl | 8 ++++---- 5 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 docs/src/examples/forward_mode.md create mode 100644 docs/src/examples/reverse_mode.md diff --git a/docs/make.jl b/docs/make.jl index 59754f0..d29ab4f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -16,6 +16,10 @@ makedocs( authors="Lyndon White and other contributors", pages=[ "Introduction" => "index.md", + "Examples of making AD systems" => [ + "Forward Mode" => "examples/forward_mode.md", + "Reverse Mode" => "examples/reverse_mode.md", + ], "API" => "api.md", ], strict=true, diff --git a/docs/src/examples/forward_mode.md b/docs/src/examples/forward_mode.md new file mode 100644 index 0000000..467c22f --- /dev/null +++ b/docs/src/examples/forward_mode.md @@ -0,0 +1,15 @@ +# ForwardDiffZero +This is a fairly standard operator overloading-based forward mode AD system. +It defines a `Dual` part which holds both the primal value, paired with the partial deriviative. +It doesn't handle chunked-mode, or perturbation confusion. +The overload generation hook in this example is: `define_dual_overload`. + +````@eval +using Markdown +Markdown.parse(""" +```julia +$(read(joinpath(@__DIR__,"../../../test/demos/forwarddiffzero.jl"), String)) +``` +""") +```` + diff --git a/docs/src/examples/reverse_mode.md b/docs/src/examples/reverse_mode.md new file mode 100644 index 0000000..a3dee93 --- /dev/null +++ b/docs/src/examples/reverse_mode.md @@ -0,0 +1,16 @@ + +# ReverseDiffZero +This is a fairly standard operator overloading based reverse mode AD system. +It defines a `Tracked` type which carries the primal value as well as a reference to the tape which is it using, a partially accumulated partial derivative and a `propagate` function that propagates it's partial back to its input. +A perhaps unusual thing about it is how little it carries around it's creating operator's inputs. +That information is all entirely wrapped up in the `propagate` function. +The overload generation hook in this example is: `define_tracked_overload`. + +````@eval +using Markdown +Markdown.parse(""" +```julia +$(read(joinpath(@__DIR__,"../../../test/demos/reversediffzero.jl"), String)) +``` +""") +```` diff --git a/docs/src/index.md b/docs/src/index.md index 50bceec..d29896f 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -57,29 +57,4 @@ When the rules are refreshed (automatically or manually), the hooks are only tri `clear_new_rule_hooks!`(@ref) clears all registered hooks. It is useful to undo [`on_new_rule`] hook registration if you are iteratively developing your overload generation function. -## Examples -Here we define two fairly simplistic operator overloading based AD Systems to demonstrate how this is used. -### ForwardDiffZero -The overload generation hook in this example is: `define_dual_overload`. - -````@eval -using Markdown -Markdown.parse(""" -```julia -$(read(joinpath(@__DIR__,"../../test/demos/forwarddiffzero.jl"), String)) -``` -""") -```` - -### ReverseDiffZero -The overload generation hook in this example is: `define_tracked_overload`. - -````@eval -using Markdown -Markdown.parse(""" -```julia -$(read(joinpath(@__DIR__,"../../test/demos/reversediffzero.jl"), String)) -``` -""") -```` diff --git a/test/demos/reversediffzero.jl b/test/demos/reversediffzero.jl index d80bb99..a410ad5 100644 --- a/test/demos/reversediffzero.jl +++ b/test/demos/reversediffzero.jl @@ -19,7 +19,7 @@ struct Tracked{F} <: Real propagate::F primal::Float64 tape::Vector{Tracked} # a reference to a shared tape - partial::Base.RefValue{Float64} # current accumulated sensitivity + partial::Base.RefValue{Float64} # current accumulated sensitivity end "An intermediate value, a Branch in Nabla terms." @@ -29,15 +29,15 @@ function Tracked(propagate, primal, tape) return v end -"Marker for inputs (leaves) that don't need to propagate." -struct NoPropagate end - "An input, a Leaf in Nabla terms. No inputs of its own to propagate to." function Tracked(primal, tape) # don't actually need to put these on the tape, since they don't need to propagate return Tracked(NoPropagate(), primal, tape, Ref(zero(primal))) end +"Marker for inputs (leaves) that don't need to propagate." +struct NoPropagate end + primal(d::Tracked) = d.primal primal(d) = d From dc116fd551825d2e53680576a119bde2e6025e80 Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 19:07:52 +0100 Subject: [PATCH 7/9] Fix logo in docs --- docs/make.jl | 2 +- docs/src/assets/logo.png | Bin 0 -> 31296 bytes docs/src/assets/logo.svg | 27 +++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 docs/src/assets/logo.png create mode 100644 docs/src/assets/logo.svg diff --git a/docs/make.jl b/docs/make.jl index d29ab4f..5fa74e7 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -12,7 +12,7 @@ makedocs( prettyurls=false, assets=[indigo], ), - sitename="ChainRules", + sitename="ChainRules Overload Generation", authors="Lyndon White and other contributors", pages=[ "Introduction" => "index.md", diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e6ebdcd11defeb333376b696cb7b59f0f28fdd15 GIT binary patch literal 31296 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
65><3gHOizU!N0{W-70UfcLHf(+g(E_*Jrs5j zFaM2m$}e539LGjZJXw-F*?U~R>1XpjVYX))J0Xh&oe-s>F|UBoN%h`WB9f1wrgobG zFi>j$ecAh-Sh8CL*h)&C5irvNzVkwhRop4Bj=A^Z8X-u#+K>%D$zSul>wR0;Q)F)f zKzP|v=yzYXxFYAiuo(?=ZW}NWq%F8K7kiEP9c0V2{*ff45CzjnQ|GgG!)KcDO^_LT zC@+Fb3(Z}pu0uKYt*WawRrSJ1O!oZxD3Z^P3}Ocl-A!Lq$$|T36fAUIRz)VckgZU? zLwjkJf_E`FnLP9HDXt)e3D}Y_g!(*V+DoNt z@n=t5mdD*CSl?3l^{24{g;q3p**oh^_p8}vd|0%Dh9sj<^ca16JOS)@NwYVII(h$R^__fqt}to?xXYaM9dFGex0S z-ZyvqFhdj}iKz;UyfbUld_wFF>D3~5Ifvod^$&cn{XBfYdR_&dlCgDg>s7R~CAZzr zPRq5Hh2(!x7vq}wx9C6hTp!t6tI+wBsd2-5%B5Fe^Cy6#GFmQ@q82}@YUC0;0f|TQ zK+eeNT)LU&_%{@oFE2YKlr-*F@lx!ugg13YkfDzrsRiQ!R14LCOhhNM1iYg^R7U5( zm?J(9>^t(POvK0mvZ_fu9ijX_|! zNwc<#FKJ!oiW~WPre!j$eq!u)Y}>HzBM+5)xslbBwM;(57u2t zmP$d*CBu;sX6bu^bW`WK`_7HxLGJDg^qMMdxv{%=Jli@rZDCf^;|9qo=lc1P3O>u0 zhMy-!%Qh1sz_XuNJmGgoUWx8HqkU9;bZbsbD3bJfTg$MmgWwU-Nl`}I1or~0ro0GC zj$waw8(rxpBoM#om9s`^WQK%W-kMZ4)g1nLK=_TQmdu}j({*Oh+h9fJpYKs_@4SBF8}!o$a^O_XS%)Ue_t9$DVrxHTn%utQ z5#;B~<^A$JuY3}{_%ED+NH<1mttW--vfX_cqe+6h)TT(^Nl4t~GimY&-2B*wL0d0? zOf?2Jw`4k%e1rZ7rS=;j4LdcHkw7sJhAY2a0b*Z5z>5iYu zhkIk`y1HW4Ein}9C&dvS)Mny1Dt|Qn_Q6dGvv#luaZV+OagUkG;|r(#jvYEY6T1b{&9M-?n| z94?QM5l9aNS3mMT)?2|sL;!uhq$4N^OsH7aOd^A60Px4>Z~N&S6n=A`AIkuH4-kWb z>K8Z`M;h=vkW&3t^1}3*%aH={AH!<@^Drv!U|$DCQ|c#T{-O=vzA5_-3D3I7hl|Mp zVODw76z7Y2RCBFGg$*Hv9~r_PpvMksK)c5#3WI>dV+i!eOx(!{qS9ZlYSH02eLkSj zm8EOjZ!{^(|a~oKO^V77Q*pSuIX0B6Q_^lNs06Pr`vZZwAD*bJe_mA?Yp-R)Pv2i4@ z3v_R<$7~>VqKd_*@9plLf?L7)e$d&u+*F8y>lx=_Piq>Ay=oH{)HJJhdVzMX?@}CM zKfbQ+d&rbzgBP#Y7ZCO(Dge2|^2s%*0(nJBo*4^jFjb|TcLo$E&ZtHfQ+isUArl=L z`#V=&wF*Pc5i~9Nqp31G#rjS^o&nfGjpSq@b1W}U=&jtrfJhM(ARPH!TqfH3H0L!N0CtWKfhZijHkz-b+MVdO9mm&C_m8E14Mt7AYy_Bb*fS-hok?Z;4 zzkbJEsK2u(mt|s?kjN{}OAMQ7RjD~FSg`-;Zpzb^2m=1B7o)t&2dp|%4gMq={Q(pe zsYboPrxCL34^)tBOUloa-5O*5Y=Y|`4Cg=qmPT392g1+B$-z|tp;NRi+bPxQX!bKt z06u3~5k7@ej~T$Z$@7?5$&4Cvg&lhgf<4ZRIwf^1INgeS($&48AbmE;xL;9C*RS_8 zWX$aOCiiXfr2`J%oC9Ac_#6ak5hp&^?ib_HV(tydmf$hCE{6L#R zLH(wB0OoCh@vrzLt(z_fRX$>;`^aJKx*15Z&rq5m!4j_iG$2p$w`VhXrYsA?yzAB& zj6E+eI_sFtoTtHBc<-Z$grMCR-5nu{su2|9mArbDsb%@hMlqQ`dGdEe+y9Nl3|)O7 zAcCa_ko%Lu=H+bpKZ<##Pe)B#A%tYJHs{!(-FnG>D!wSdE1cPJ#Y$bAmsmxL`~h!w z1M_ZB1M$}bhQ%<&TJ*7UfWR$xBW!F)(#hV=`nzFJe3MKI8o-alWl<9D`it{k@;Y@p z*3c^A&nnJ>v4#qSlV3QHW7I%&Ab7uv_EL)7ICY5ZH|PaU)8IE;dlDFSBKZfjDD^NK zMrfJogs#{aRc;@PZ3dabcjp3pgUaEhb`J7OxUXVE(M=u^%y1VdYPLfvXV*(qg&iPJ zgW!~78@5#Ow7P)Kcl6w35-SXjL&7jU;cPraOZHw!n#g-RZBfJgqr(lp&nn73q_mgC2lmSuNMsKlgmIk9p? zH^W=9FX$P7iGx!7G<>hiNr0h_7`;=97hylQi;7Z083w=laKBr8E}5qR5pyr`oUoMrjr5xKNH}*O2BIG1-28SR6BSffN^|)cadq z?7PAz@sos>pvldWa4niCu3&unI!VkmZ{OZ13hKPe3XawYKx^e|pjS6)-&@iH+EQ2k zd~M%k{{0FY<>ugjBcTtp!y~K5PvzjuTdnEuiUxo>>}E_oi#B^(#5Dy0&G`Slsg5t2 zKMBm29QA@BY3Op8Q+f+&=i3M`P}xrk$+o9z3x`V?TL6}+*B1df5Grws_->$lzGJ|% z2pUB>cZ%Ygd4v82fw>){2PC4hSyabNfA=>-nT)1^MZ^aNfsSA5qDlbycQuT7+sxya z5{M;Mrql9qhu?6d7F3k*W=2S+y@X2GzeE0iPdW1g)Di3fXbyOe65O{1a(W2aL$$p9 z^5%O^DbU|2A#$;-~euYtVGCZwphxDp-N?&8~ z`4?RZ;mCkgBTVZP6tK%d8O*gc)eZIrF8%dkfZnB9E-_8yq{nF>UwvRv+ovk<(Ptah zml?z2|L^AFd)g2_5S7JpfpWZ`K=ngze{RYzUvj}d@}o9TzQRBnqIo1^ZK_Uf{j3@3 z^{x#raIz41x*7i%luE5V!tFv)Z)&drLknltL4JKN3|uy{?zaeH=QuUP*YiO{^=~Z- z_5xM~Uk+3RtAY=$=Sn`OA~hM^@pP-Ni$`MaWNmi!jC+D#v3;WLyM!4&6Vh5OkT+`O z{m*g)y|=c~KmbQ|fN#9|<%s-Eh9^0^El+etVAL!g{VztP=Q3L|_TOb5B3%3IVpG9q zYwA3}|EJCZPuYCEA{QZn5`x|24dI14k=kVjT4lh74&PXzjQ49eg;(er@n0ls3?Qvk4lV-9nUpz6@hMS=0r{YtXGWPolV4J$+GA*7P zlh*3=sq2LshNQQ9|Jh;l-9r2ma>q>S6$6#=X`({Y`|py<1g8!e8xd&EKtF)3zXM5e zX**v5L$Fhm@6YT~fEXCN;|Dh{p z+vX-a5!j{mSglo?{-se*ur#BLZXs;+M1mZUNkIs@?ha=E;rZU+RZ#qSCE+qqW0{=H z1qS*_36*fxlQkeu#l!c`)%g??1wNjMXh(rVj|QekAVfL*k`Y4;I~| z{KGF{$f?<|b@=>J7>c#3wVHIt6vh$?zqdq<`)+DKG4<qfQcxxg)np3dF7EtYM3?^_SB`1p znEdd_zspvJJxh|uA0HM16_`+x_Ca;6SZ`+_+L}r*{k)ZmXd`pGCDS`x*1K!QYk0@W zo>Ia7h%|6k?7l<(lii0oExHu^6_hn45Cx=i0DCC{Zn)vG%B#vV$v;p3{gN=relOwx zWYr<+C#&!f!FllPyI5vISv*UzXC9$I1e^i1CrPDS1-V!i<- z=O_e6VQ0dXSeg)ec3(;d@06v9)@Row9T&Jk0u zU;v)I9OZuHv0p#FS%P}ixy_TY0f9>U5k^9Qq}u_urswwE^YzA8(xha)&hCgGsQj(C zC5yP~ep|lb#}1@@bVB=Wdu6KOk#E_aXdJ@E#)S~s!qsQdG4hw95|NicOpi}5#Ye6I z@l6TfIgI8HRVJgK6B%-($PK^N2pKUj^x1GG-1pXJKSeXNEYK(4KWTY0N->r+)|j@3 zS_DWI#{o*=?EJb2P+R@_5!qfZ1JQQ{7h9nF4ta^&>RZ6j0Ado)r4XL>lPd$TZRaU3 zv2R#eQ45w0n0EVVR+3tfQWU0bMpC=QM$y9e9%0KVL7VgPcoXnKsT1HWZD8pP;>mVT z%TXK3N8JJ(n6!iD9e-)xY{qiU@@Hsiz6fBTVidUZ@Mi>cYT!%XCAR`+G44S2%` z-)1*fX9Cek$UNT3wU>4*44idZcz>{&{Ncw%2kT;tm*t~mN9qIhDtlJL(O)FrcLc(Y}R9xMV_ z@*dUElyKYAY)x@nuBf@pBQ-0zZfo@Q(s%mVw*lWpJ_`H z%MiFVr^~jbhjyEB&1J>&bd)Ocb1!XKn%bPDbj6r=ZxxVK8Lhv2u@PJRor(_sJX(US zzkvpV)XX`9xB9WeMd?wm0xfo^y3h{LbvpbjrTkD;bdbjW=|TK0UfCmt&h+rwV#Jbg zHY`M+JDyUe0N(l2anVgw|I_l}E1Ah8zFmEQz%E_B$?EU5R=l6lk&J9vMtKmFltp7l zZwsNQN(Fu5V*Wlqe2}8<+JqYuG%LIK)H^6V2DU;b$3y# zyTDx-J=OVpgOjb#NPic+hdS6#A?iqvP?DM;0n5ncc`zsXIh@FY0&%g!m1ie{INymO zOQKq8j}R|gettJ*>rFJ(zJ@*3`4SpHMpD$&cqqQg+C#qaZ&a$iw?rYBmWx|HFDEZ` zFtJso?l^DYtBj@^*HNY_Y|U?F^qoFE17}+2r9Dwml5)C|f_<+mpsF`?e_m0napXNk z5Z9ZxWzPm!#6SI5P5~ThvG^%o9wr~7@QrsvkUh&uf{4DS4JZWn>{sph2q5UEw@YSA z%^cip5g3Fl*N(9p${(XX1JZmRro|a4&2Ly2i}h_XQbRPr>3vxUfmnP4?2ukNL(a-x ztKZ4(Zhth@utI2QY;OWSUCvWFV6v0Dl6%Y=*(o_o5Z)vw3TE7^<;s-``d?PDl2N zIMLF7;zk<}!fJIdpKmWh$K(_71jD$t!U1uI_fEJ z2~tzc;sUUUDQ3KRhhj&0&E7r;T;-3wDCb|o6|Si`dxhKoDFMI%7>>>^`H|GzB7~q-_RU8yX)h- zk#rFo7JJoujt5Tq#3Nv0y36-3Qwx#)Vz(4JFhaY@c(isdThO#NF&e`0xQ~p)=O;Pq z=XEYC070c_`9CB8mIKgHFF+9hU|n5bA^sgh9bXlq8L9{EeSvMy2+@!|z0`lAwiF0( z+^%R&nYnMG2w=M={GV-{@)XP($_uKYjRRkY0Bx(0W)Io+dELeRw9DGA1zPRkt;SS1 z6Et9a#Ew>f8LbpW1Q43Xj!&ug0q;8GlSPRG&-OnZtb_~>P)@(=$g_P77~~TSG9DmU zxSJ|y`c+F)jSx`wedMH)&{}r(Zr@kf7m5N|p|eXb6k$NI4Hz+@a9*neUrUPx)(wp% zc_7-o>aoM#J*~5U-fu2GfuqeKX+dgs(>_6EE6nn2#B3}m$Q3_cc0?AskrYDnXxOISG$eQY+ zck)WvlL)R0S4Z%Fr8rqUO;?r0lt>q==8`;1GbJxqvl)T2<_}z@Zae<*8h_E2M~S~} zxW0T!+J>8%+4!A5FH@7Oke^Vs7S^nXmK}}Q2pvp+X8tTtrXpZFp>g+bFMZ~D`iZwH zwQ7+qyP^VvOo$5GjtlttAe*}RXHMebRZM*Uf+-hhZY(JMLV|b(_P+j~lFs}YcPa_m zH0QRgnAnOD3}SEKUZJvwoQZ}B(=dCQ*}p>RLISAKSmFXs;8mQR7$;FAtN*8Wp#Ufkdu(K<1XB4^9_58@yB42itUZXu!28~- zzwQbFKl9^Ss65b`f>dz`h$M_Rb@pgOpB)b=>k(+`FlS-|>mofk6uE&hD;gN2Zp zUcw;w=znoMNh=GPjjBACM~2^O=Q@;D{h>XtGMKGyX}m#&t}wq zcii~B1#P?j%HZnL?e0O8GqFLHcg(8t>RMy@Zrb{TzuM-RQ@|6NeL&urj=K~J5NMEk zDQRa2Ldj#E9j#J*o!|07DxGg@W0R3|H*GkZoBNvA%6PghX->Oc;C!1M2w9~4y{^D! z!>NI(-%SM^{fWy=0zB{dzw_zBXJ58Svi#f#SKJ+-?cxp5-HwuP0v534;Zdw(+6K6(BAY34G69EbX!E7jtWR8Kvzz`r5YH9Kia`T7va7y8JY-?SU6j69iW!!met8xH z0KolEh4AHA4yb_Ljj1ZPN8SH>YPuWF*L>D}M?!@sPFVXPzf67W71P!O@nM(mNU-#6 zi#uL+By_x+Qn83`nKI}#Rw(3lKrTojWKnp_tk5S?r2V82#gF@at}3f!2CO1*y>aQ8 zKOl=*a@z_imCCpQ{41B%uoeH>M9RAB+rpzI=aMpW{TWaYRYq2cd#3*8IZOH7>QQyB3AZZUIbcY*(Wef-PRoyq3}#sJBcOQ)>2u0D@qE z4G=n_tQ>gBD~|`uGWFOt?N8g&qlrMulQ6!K+E#i2~ zVx*a3q`)V;tdaWH;<`;Pn#Z+Q@AlTU%n+L#&A zzM>|jg(8-wv&*wiVER3C0KU@8K#rzEF_E9B`HrFr;__9}(y`jU757bqcDW150!oPV pWdh(})BpDz<^SJ*yDOjZRMYz36hsV~14lxGK1wM_mc#UZ{2!N<+hqU% literal 0 HcmV?d00001 diff --git a/docs/src/assets/logo.svg b/docs/src/assets/logo.svg new file mode 100644 index 0000000..1e8f0ad --- /dev/null +++ b/docs/src/assets/logo.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1dd93459fe136d0428e9903bc8eecfdc36024b8c Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 19:35:52 +0100 Subject: [PATCH 8/9] use first not only in tests for 1.0 compat --- test/ruleset_loading.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ruleset_loading.jl b/test/ruleset_loading.jl index 201c714..4f3b02d 100644 --- a/test/ruleset_loading.jl +++ b/test/ruleset_loading.jl @@ -72,7 +72,7 @@ @testset "_is_fallback" begin _is_fallback = ChainRulesOverloadGeneration._is_fallback - @test _is_fallback(rrule, only(methods(rrule, (Nothing,)))) - @test _is_fallback(frule, only(methods(frule, (Nothing,)))) + @test _is_fallback(rrule, first(methods(rrule, (Nothing,)))) + @test _is_fallback(frule, first(methods(frule, (Nothing,)))) end end From 6c9660b2165c072c5c05997da3d4531bb78f2226 Mon Sep 17 00:00:00 2001 From: Lyndon White Date: Wed, 26 May 2021 20:19:52 +0100 Subject: [PATCH 9/9] Apply suggestions from code review Co-authored-by: Nick Robinson --- README.md | 2 +- docs/src/examples/forward_mode.md | 3 +-- docs/src/examples/reverse_mode.md | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 241a40e..6d4ada9 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,5 @@ [![](https://img.shields.io/badge/docs-master-blue.svg)](https://juliadiff.org/ChainRulesOverloadGeneration.jl/dev) [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadiff.org/ChainRulesOverloadGeneration.jl/stable) -The ChainRulesOverloadGeneration package provides a suite of methods for using [ChainRulesCore.jl](https://github.com/JuliaDiff/ChainRulesCore.jl) rules in operator overloaded based AD systems. +The ChainRulesOverloadGeneration package provides a suite of methods for using [ChainRulesCore.jl](https://github.com/JuliaDiff/ChainRulesCore.jl) rules in operator overloading AD systems. It tracks what rules are defined at any point in time, and lets you trigger functions to which can use `@eval` in order to define the matching operator overloads. diff --git a/docs/src/examples/forward_mode.md b/docs/src/examples/forward_mode.md index 467c22f..31a632e 100644 --- a/docs/src/examples/forward_mode.md +++ b/docs/src/examples/forward_mode.md @@ -1,6 +1,6 @@ # ForwardDiffZero This is a fairly standard operator overloading-based forward mode AD system. -It defines a `Dual` part which holds both the primal value, paired with the partial deriviative. +It defines a `Dual` part which holds both the primal value, paired with the partial derivative. It doesn't handle chunked-mode, or perturbation confusion. The overload generation hook in this example is: `define_dual_overload`. @@ -12,4 +12,3 @@ $(read(joinpath(@__DIR__,"../../../test/demos/forwarddiffzero.jl"), String)) ``` """) ```` - diff --git a/docs/src/examples/reverse_mode.md b/docs/src/examples/reverse_mode.md index a3dee93..97dcabd 100644 --- a/docs/src/examples/reverse_mode.md +++ b/docs/src/examples/reverse_mode.md @@ -1,8 +1,8 @@ - # ReverseDiffZero + This is a fairly standard operator overloading based reverse mode AD system. -It defines a `Tracked` type which carries the primal value as well as a reference to the tape which is it using, a partially accumulated partial derivative and a `propagate` function that propagates it's partial back to its input. -A perhaps unusual thing about it is how little it carries around it's creating operator's inputs. +It defines a `Tracked` type which carries the primal value as well as a reference to the tape which is it using, a partially accumulated partial derivative and a `propagate` function that propagates its partial back to its input. +A perhaps unusual thing about it is how little it carries around its creating operator's inputs. That information is all entirely wrapped up in the `propagate` function. The overload generation hook in this example is: `define_tracked_overload`.