A demonstration of source code transformation to implement automatic differentiation, compatible with an operation overload style AD library DiffKt.

Overview

AdOptimize Kotlin Plugin

AdOptimize is a Kotlin compiler plugin that can transform functions written using an operation overload automatic differentiation library (OO AD) into a function over Kotlin Floats that returns the derivatives and primal value (SCT AD). It also includes a proof of concept feature that transforms functions over Kotlin floats into a function that returns the derivative.

AdOptimize is not recommended for use in production; it is a research project. AdOptimize is unique in that the functions it produced may interoperate with functions written using the library.

AdOptimize is also a proof of concept of the IR-serialize feature of the Kotlin compiler. When this feature is enabled, the Kotlin IR is serialized into the class files of a compiled JVM program, where it can be extracted by the compiler during the compilation of a consuming module. The benefit of this feature is that it enables a view of the entire program, which is a requirement for many optimizations including inlined derivative code.

Features:

  • Removes the object wrapping that OO AD depends on via performing the differentiation via source code transformation. This is supported for reverse mode and a combination of forward and reverse mode (a variation of second order) over scalar functions. Only one active parameter is supported. (see adOptimizeClient/src/main/kotlin/client/main.kt for an example. The function target over DScalars is an example of this unwrapping. The annotation @SecondOrderOptimize and @Optimize indicate that both the first and second order derivatives shall be generated by AdOptimize)
  • single parameter reverse mode differentiation for Kotlin Floats (see adOptimizeClient/src/main/kotlin/client/main.kt for an example. The function target over Floats is an example of this prototype)
  • control flow

From Source Usage

  • download or clone repository
  • publish the api locally using the gradle command publishLocal
  • Create a client project. Depend on DiffKt and create an ADConfig file that matches that of adOptimizeClient/src/main/kotlin/AdConfig.kt. The annotations can have custom names but if you change them you must also change them in the build script in the following step.
  • clone the gradle build from adOptimizeClient/build.gradle
  • Write a function using the @Optimize annotation and test the performance differences. See adOptimizeClient/src/main/kotlin/client/main.kt for an example.

Testing

  • To run the AdOptimize and DiffPrep IR and codegen tests, run ./gradlew integrationTests.
  • IR tests are programs that accept a text file of source code and a text file of expected serialized IR and verify that the source code, when compiled to Kotlin IR and serialized, matches the expected serialized IR file. These tests are useful during development to verify stubs have been generated correctly. It's common to produce the expectation file by coding up what you expect the compiler to generate by hand and serializing the hand written file. Note that if you delete the expectation file the test framework will generate a default one based on the source file and fail the test.
  • Codegen tests are programs that accept a text file of source code, where the source code contains a box() method. The test fails if the box method does not return "OK". Codegen tests are the primary form of testing in the compiler environment.

Components

differentiable-api-preprocessor The differentiable-api-preprocessor plugin (DiffPrep) is used in the compilation of the operation overloading library. The tests in AdOptimize rely on the operation overloading AD library DiffKt but there is no reason another implementation cannot be used. The OO AD library annotates key components of the library such as the differentiable scalar type and binds the fully qualified name of the annotation to a key defined in DiffPrep. DiffPrep will produce a configuration file for AdOptimize to consume during a client application's compilation.

producer-consumer The Producer Consumer is an independent top level project that demonstrates the usage of a client application that uses AdOptimize but relies on a custom OO AD library. This is a good demonstration of the build script configration.

adOptimize AdOptimize contains the AD generation code. The work flow is Kotlin IR is translated into DiffIR, a subset of Kotlin IR wrapped in classes that store pullback and active information for each statement. There are reverse and forward mode passes that accept DiffIR and return differentiated Kotlin IR. The intention was for the IR returned by each pass to be eligible for transformation back into Diff IR so that multiple differentiation passes could be applied, therefore supporting arbitrary orders of differentiation and combinations of reverse and forward. Only the Reverse-Forward combination was ever tested.

plugin-generators-common In order to map to DiffIR, the Kotlin code must be lowered. A lowered language makes code generation easier because it reduces the number of constructs that must be supported. For example, we unnest all expressions so that every operation has a variable. The lowering in this module are used by both DiffPrep and AdOptimize. This module also includes extensions of Kotlin Compiler types so that functions and classes generated by the plugin are visible to consuming projects. See GeneratedAuthenticClassDescriptor.kt and ClassLifter.kt for details.

adOptimizeClient The adOptimize client is an independent top level project that demonstrates how to use AdOptimize with DiffKt.

Below is an illustration of the relationship between a client application, DiffPrep, and AdOptimize. plot

Code Generation Example

What does AdOptimize generate? Let us suppose we are given the following code:

@Optimize
fun target(a:DScalar, L:Int):DScalar {
    var i = 0
    var s = a*a
    while(i<L) {
        s = s * (s + a)
        i = i + 1
    }
    return s
}

AdOptimize will generate a class ReverseScalar that contains an implementation of the pullback of the function defined above. It will look something like this:

fun target(a:DScalar, L:Int):DScalar {
    class target_Reverse(val a:ReverseScalar, val L:Int): ReverseScalar(FloatScalar.ZERO, a.derivativeID) {
        override val primal: DScalar
        val decisions = CodeGenStack<Any>()
        val intermediateValues = CodeGenStack<Any>()
        init {
            val a_primal = this.a.basePrimal().value
            val L = this.L
            var i = 0
            var s = a_primal * a_primal
            while(i<L) {
                intermediateValues.push(s)
                val intermediate_variable_0 = s + a_primal
                intermediateValues.push(s)
                intermediateValues.push(intermediate_variable_0)
                val intermediate_variable_1 = s * intermediate_variable_0
                s = intermediate_variable_1
                val intermediate_variable_2 = 1
                val intermediate_variable_3 = intermediate_variable_2 + i
                i = intermediate_variable_3
                decisions.push(-1)
            }
            this.primal = FloatScalar(s)
        }

        override fun backpropagate() {
            val a_local_0 = this.a
            val a_local_1_primal:Float = a_local_0.basePrimal().value
            var a_derivative_2 = 0f
            val L_local_3 = this.L
            val s_local_4 = this.primal
            // Note that in reality this is checked to make sure upstream is a DScalar and not a DTensor to support multiple outputs. Here I removed that check to simplify the code generation demo
            var upstream = (this.upstream as DScalar).basePrimal().value
            while(this.decisions.notEmpty() && this.decisions.top() == -1){
                this.decisions.pop()
                var intermediate_variable_1_derivative_6 = 0f
                var intermediate_variable_0_derivative_8 = 0f

                intermediate_variable_1_derivative_6 = upstream
                upstream = 0f

                val intermediate_variable_0_local_9 = intermediateValues.pop() as Float
                val s_local_10 = intermediateValues.pop() as Float
                val up0 = intermediate_variable_1_derivative_6
                val l = up0 * intermediate_variable_0_local_9
                val r = up0 * s_local_10
                upstream = upstream + l
                intermediate_variable_0_derivative_8 = intermediate_variable_0_derivative_8 + r

                val s_local_11 = intermediateValues.pop() as Float
                val up = intermediate_variable_0_derivative_8
                upstream = upstream + up
                a_derivative_2 = a_derivative_2 + up
            }
            val l = a_local_1_primal * upstream
            a_derivative_2 = a_derivative_2 + l + l
            this.a.pushback(FloatScalar(a_derivative_2))
        }
    }
    return when(a){
        is ReverseScalar -> target_Reverse(a, L)
        else -> {
            var i = 0
            var s = a*a
            while(i<L) {
                s = s * (s + a)
                i = i + 1
            }
            s
        }
    }
}

Note that the primal function is also transformed in order to only return the optimized code under certain conditions.

License

AdOptimize is MIT licensed, as found in the LICENSE file.

You might also like...
A powerful tool (iOS & Android) that focuses on mobile operation behavior!
A powerful tool (iOS & Android) that focuses on mobile operation behavior!

DiDiPrism,中文名:小桔棱镜,是一款专注于移动端操作行为的工具,涵盖APP操作回放、操作检测、以及数据可视化能力。我们在整个方案的实现过程中沉淀出了一套技术框架,希望可以逐步开源出来帮助更多人,同时也希望棱镜在大家的合力下能够更快的成长。 它有哪些亮点? 零入侵 业务代码无需任何适配。 高可

Keep data as a linked list on disk. A alternative way to reduce redundant operation for DiskLruCache
Keep data as a linked list on disk. A alternative way to reduce redundant operation for DiskLruCache

DiskLinkedList Keep data as a linked list on disk. An alternative way to reduce redundant operation for DiskLruCache Use-case Android have build-in Di

VideoTimelineView - A TimelineView implementation for video cut and trim operation
VideoTimelineView - A TimelineView implementation for video cut and trim operation

VideoTimelineView A TimelineView implementation for video cut and trim operation

Learning kotlin CRUD operation with SQLite
Learning kotlin CRUD operation with SQLite

Students App Other useful features CRUD operation SQLite integration Google Material Design library Resource defaults colors.xml - colors for the enti

BaseAnimation network Android animation set, custom controls, nearly 200 kinds of source code! BaseAnimation, if a new version is updated automatically to remind everyone, I hope everyone will contribute their animated XML files or other source, together to create this open source app!
Automatic CoroutineDispatcher injection and extensions for kotlinx.coroutines

Dispatch Utilities for kotlinx.coroutines which make them type-safe, easier to test, and more expressive. Use the predefined types and factories or de

A study into creating a fully automatic FRC robot

AutoFRC This is a study into creating a fully automatic FRC robot. This process relies on several key algorithms: pose estiation: using the WpiLib Dif

Automatic Blue Archive (Global) decensorer

Cunny Archive Automatic Blue Archive decensor patch Works with both Android 10+ (using scoped storage) and older Android versions (using legacy storag

Automatic Slider with jetPack Compose
Automatic Slider with jetPack Compose

Automatic Slider with jetPack Compose

  An IoT based automatic alerting device that consists of laser and a precise Light Dependent Resistor to detect the laser which is employed to constantly monitor the fluid level
An IoT based automatic alerting device that consists of laser and a precise Light Dependent Resistor to detect the laser which is employed to constantly monitor the fluid level

An IoT based automatic alerting device that consists of laser and a precise Light Dependent Resistor to detect the laser which is employed to constantly monitor the fluid level. When the fluid level is below the critical level which will be defined by laser, it will alert the patient through buzzer, nurses and doctors through mobile app and the …

AVTS App - S.I.T Global PBL 2021 - Automatic Visitor Tracking System Android Application

S.I.T Global PBL 2021 - Automatic Visitor Tracking System Android Application De

Parking Robot based on 3D LiDAR. Keywords: Automatic Parking, SLAM, 3D Navigation, Remote Control, ROS, RRT
Parking Robot based on 3D LiDAR. Keywords: Automatic Parking, SLAM, 3D Navigation, Remote Control, ROS, RRT

ELEC3875-Final-Project My undergraduate final project: Parking Robot based on 3D LiDAR. ELEC3875 / XJEL3875 Keywords: Automatic Parking, SLAM, 3D Navi

LiveEdgeDetection is an Android document detection library built on top of OpenCV. It scans documents from camera live mode and allows you to adjust crop using the detected 4 edges and performs perspective transformation of the cropped image.  It works best with a dark background. An Android transformation library providing a variety of image transformations for Glide.
An Android transformation library providing a variety of image transformations for Glide.

Glide Transformations An Android transformation library providing a variety of image transformations for Glide. Please feel free to use this. Are you

An Android transformation library providing a variety of image transformations for Picasso
An Android transformation library providing a variety of image transformations for Picasso

Picasso Transformations An Android transformation library providing a variety of image transformations for Picasso. Please feel free to use this. Are

An Android transformation library providing a variety of image transformations for Coil, Glide, Picasso, and Fresco.
An Android transformation library providing a variety of image transformations for Coil, Glide, Picasso, and Fresco.

An Android transformation library providing a variety of image transformations for Coil, Glide, Picasso, and Fresco.

MIPagerTransformer is an android library that provides a seamless image transformation experience.
MIPagerTransformer is an android library that provides a seamless image transformation experience.

MIPagerTransformerView -- MIPagerTransformer is an android library that provides a seamless image transformation experience. Overview 👆 Shutter 👆 Pa

iOS style scroll wheel (style similar to UIPickerView)
iOS style scroll wheel (style similar to UIPickerView)

WheelPicker iOS-style scroll wheel picker Read this in other languages: Feature Day / Night Mode Support Customizable style Support circular scro

An AutoValue extension that generates binary and source compatible equivalent Kotlin data classes of AutoValue models.
An AutoValue extension that generates binary and source compatible equivalent Kotlin data classes of AutoValue models.

AutoValue Kotlin auto-value-kotlin (AVK) is an AutoValue extension that generates binary-and-source-compatible, equivalent Kotlin data classes. This i

Owner
Meta Research
Meta Research
Showcases different ways of writing backwards-compatible Gradle plugins.

manifestprinter This project showcases different ways of writing backwards-compatible Gradle plugins. It accompanies a talk held at droidcon Berlin 20

Simon Schiller 5 Jul 12, 2022
EasyVersion is a Gradle plugin that manage your app or library version.

EasyVersion EasyVersion is a Gradle plugin that manage your app or library version. Before Downloading Create easy_version.json in your root project d

Kosh Sergani 8 Nov 26, 2022
Gradle plugin that generates a Swift Package Manager manifest and an XCFramework to distribute a Kotlin Multiplatform library for Apple platforms.

Multiplatform Swift Package This is a Gradle plugin for Kotlin Multiplatform projects that generates an XCFramework for your native Apple targets and

Georg Dresler 262 Jan 5, 2023
A non-linear problem solver using automatic differentiation and penalty methods.

HelixOptimizer Join the discord and contribute! https://discord.gg/kqe74EER A non-linear problem solver using automatic differentiation and penalty me

Triple Helix 0 Oct 18, 2022
comtomize view submit button which you use for submit operation or download operation and so on.

This is library project with a custom view that implements concept of Submit Button (https://dribbble.com/shots/1426764-Submit-Button?list=likes&offse

ZhangLei 129 Feb 5, 2021
LiteGo is a Java-based asynchronous concurrency library. It has a smart executor, which can be freely set the maximum number of concurrent at same time , and the number of threads in waiting queue. It can also set waiting policies and overload strategies.

LiteGo:「迷你」的Android异步并发类库 LiteGo是一款基于Java语言的「异步并发类库」,它的核心是一枚「迷你」并发器,它可以自由地设置同一时段的最大「并发」数量,等待「排队」线程数量,还可以设置「排队策略」和「超载策略」。 LiteGo可以直接投入Runnable、Callable

马天宇 189 Nov 10, 2022
Chandrasekar Kuppusamy 799 Nov 14, 2022
A material style progress wheel compatible with 2.3

![](https://img.shields.io/badge/Methods and size-106 | 12 KB-e91e63.svg) Material-ish Progress A material style progress wheel compatible with 2.3 Tr

Nico Hormazábal 2.5k Dec 28, 2022
A material style progress wheel compatible with 2.3

![](https://img.shields.io/badge/Methods and size-106 | 12 KB-e91e63.svg) Material-ish Progress A material style progress wheel compatible with 2.3 Tr

Nico Hormazábal 2.5k Jan 4, 2023
A material style progress wheel compatible with 2.3

![](https://img.shields.io/badge/Methods and size-106 | 12 KB-e91e63.svg) Material-ish Progress A material style progress wheel compatible with 2.3 Tr

Nico Hormazábal 2.5k Jan 4, 2023