pre-0.0.3 #46

Merged
altavir merged 75 commits from dev into master 2019-02-20 13:05:39 +03:00
7 changed files with 339 additions and 64 deletions
Showing only changes of commit aaa3bd387d - Show all commits

View File

@ -1,53 +1,54 @@
# KMath # KMath
Kotlin MATHematics library is intended as a kotlin based analog of numpy python library. Contrary to `numpy` The Kotlin MATHematics library is intended as a Kotlin-based analog to Python's `numpy` library. In contrast to `numpy` and `scipy` it is modular and has a lightweight core.
and `scipy` it is modular and has a lightweight core.
## Features ## Features
* **Algebra** * **Algebra**
* Mathematical operation entities like rings, spaces and fields with (**TODO** add example to wiki) * Algebraic structures like rings, spaces and field (**TODO** add example to wiki)
* Basic linear algebra operations (summs products, etc) backed by `Space` API. * Basic linear algebra operations (sums, products, etc.), backed by the `Space` API.
* Complex numbers backed by `Field` API (meaning that they will be useable in any structures like vectors and NDArrays). * Complex numbers backed by the `Field` API (meaning that they will be usable in any structure like vectors and N-dimensional arrays).
* [In progress] advanced linear algebra operations like matrix inversions. * [In progress] advanced linear algebra operations like matrix inversion and LU decomposition.
* **Array-like structures** Full support of numpy-like ndarray including mixed arithmetic operations and function operations * **Array-like structures** Full support of [numpy-like ndarrays](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.ndarray.html) including mixed arithmetic operations and function operations over arrays and numbers just like in Python (with the added benefit of static type checking).
on arrays and numbers just like it works in python (with benefit of static type checking).
* **Expressions** Expressions are one of the ultimate goals of kmath. It is planned to be able to write some mathematical * **Expressions** Expressions are one of the ultimate goals of KMath. By writing a single mathematical expression
expression once an then apply it to different types of objects by providing different context. Exception could be used once, users will be able to apply different types of objects to the expression by providing a context. Exceptions
for a wide variety of purposes from high performance calculations to code generation. can be used for a wide variety of purposes from high performance calculations to code generation.
## Planned features ## Planned features
* **Common mathematics** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) * **Common mathematics** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/)
library in kotlin code and maybe rewrite some parts to better suite kotlin programming paradigm. There is no fixed priority list for that. Feel free library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free
to submit a future request if you want something to be done first. to submit a feature request if you want something to be done first.
* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks. * **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.
## Multi-platform support ## Multi-platform support
KMath is developed as a multi-platform library, which means that most of interfaces are declared in common module.
Implementation is also done in common module wherever it is possible. In some cases features are delegated to KMath is developed as a multi-platform library, which means that most of interfaces are declared in the [common module](kmath-core/src/commonMain).
platform even if they could be done in common module because of platform performance optimization. Implementation is also done in the common module wherever possible. In some cases, features are delegated to
Currently the main focus of development is the JVM platform, contribution of implementations for Kotlin - Native and platform-specific implementations even if they could be done in the common module for performance reasons.
Kotlin - JS is welcome. Currently, the JVM is the main focus of development, however Kotlin/Native and Kotlin/JS contributions are also welcome.
## Performance ## Performance
The calculation performance is one of major goals of KMath in the future, but in some cases it is not possible to achieve
both performance and flexibility. We expect to firstly focus on creating convenient universal API and then work on Calculation performance is one of major goals of KMath in the future, but in some cases it is not possible to achieve
increasing performance for specific cases. We expect the worst KMath performance still be better than natural python, both performance and flexibility. We expect to focus on creating convenient universal API first and then work on
but worse than optimized native/scipy (mostly due to boxing operations on primitive numbers). The best performance increasing performance for specific cases. We expect the worst KMath benchmarks will perform better than native Python,
of optimized parts should be better than scipy. but worse than optimized native/SciPy (mostly due to boxing operations on primitive numbers). The best performance
of optimized parts should be better than SciPy.
## Releases ## Releases
The project is currently in pre-release stage. Nightly builds could be used by adding additional repository to (groovy) gradle config: The project is currently in pre-release stage. Nightly builds can be used by adding an additional repository to the Gradle config like so:
```groovy ```groovy
repositories { repositories {
maven { url = "http://npm.mipt.ru:8081/artifactory/gradle-dev" } maven { url = "http://npm.mipt.ru:8081/artifactory/gradle-dev" }
mavenCentral() mavenCentral()
} }
``` ```
or for kotlin gradle dsl:
or for the Gradle Kotlin DSL:
```kotlin ```kotlin
repositories { repositories {
@ -56,16 +57,20 @@ repositories {
} }
``` ```
Then use regular dependency like Then use a regular dependency like so:
```groovy ```groovy
compile(group: 'scientifik', name: 'kmath-core', version: '0.0.1-SNAPSHOT') compile(group: 'scientifik', name: 'kmath-core', version: '0.0.1-SNAPSHOT')
``` ```
or in kotlin
or in the Gradle Kotlin DSL:
```kotlin ```kotlin
compile(group = "scientifik", name = "kmath-core", version = "0.0.1-SNAPSHOT") compile(group = "scientifik", name = "kmath-core", version = "0.0.1-SNAPSHOT")
``` ```
Work builds could be obtained with [![](https://jitpack.io/v/altavir/kmath.svg)](https://jitpack.io/#altavir/kmath). Working builds can be obtained here: [![](https://jitpack.io/v/altavir/kmath.svg)](https://jitpack.io/#altavir/kmath).
## Contributing ## Contributing
The project requires a lot of additional work. Please fill free to contribute in any way and propose new features. The project requires a lot of additional work. Please fill free to contribute in any way and propose new features.

View File

@ -1,50 +1,57 @@
# Context-oriented mathematics # Context-oriented mathematics
## The problem ## The problem
A known problem for implementing mathematics in statically-typed languages (and not only in them) is that different A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different
sets of mathematical operation could be defined on the same mathematical objects. Sometimes there is not single way to sets of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to
treat some operations like basic arithmetic operations on Java/Kotlin `Number`. Sometimes there are different ways to do treat some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to
the same thing like Euclidean and elliptic geometry vector spaces defined over real vectors. Another problem arises when define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem arises when
one wants to add some kind of behavior to existing entity. In dynamic languages those problems are usually solved one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are usually solved
by adding dynamic context-specific behaviors in runtime, but this solution has a lot of drawbacks. by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks.
## Context-oriented approach ## Context-oriented approach
One of possible solutions to those problems is to completely separate object numerical representations from behaviors.
In terms of kotlin it means to have separate class to represent some entity without any operations, One possible solution to these problems is to completely separate numerical representations from behaviors.
One solution in Kotlin, is to define a separate class which represents some entity without any operations,
for example a complex number: for example a complex number:
```kotlin ```kotlin
data class Complex(val re: Double, val im: Double) data class Complex(val re: Double, val im: Double)
``` ```
And a separate class or singleton, representing operation on those complex numbers:
And then define a separate class or singleton, representing an operation on those complex numbers:
```kotlin ```kotlin
object: ComplexOperations{ object ComplexOperations {
operator fun Complex.plus(other: Complex) = Complex(re + other.re, im + other.im) operator fun Complex.plus(other: Complex) = Complex(re + other.re, im + other.im)
operator fun Complex.minus(other: Complex) = Complex(re - other.re, im - other.im) operator fun Complex.minus(other: Complex) = Complex(re - other.re, im - other.im)
} }
``` ```
In Java, application of such external operations could be very cumbersome, but Kotlin has a unique feature which allows In Java, applying such external operations could be very cumbersome, but Kotlin has a unique feature which allows
to treat this situation: blocks with receivers. So in kotlin, operation on complex number could beimplemented as: to treat this situation: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions).
So in Kotlin, an operation on complex number could be implemented as:
```kotlin ```kotlin
with(ComplexOperations){c1 + c2 - c3} with(ComplexOperations) { c1 + c2 - c3 }
``` ```
Kotlin also allows to create functions with receivers: Kotlin also allows to create functions with receivers:
```kotlin ```kotlin
fun ComplexOperations.doSomethingWithComplex(c1: Complex, c2: Complex, c3: Complex) = c1 + c2 - c3 fun ComplexOperations.doSomethingWithComplex(c1: Complex, c2: Complex, c3: Complex) = c1 + c2 - c3
ComplexOperations.doComethingWithComplex(c1,c2,c3) ComplexOperations.doComethingWithComplex(c1,c2,c3)
``` ```
In fact, whole parts of program could run in a mathematical context or even multiple nested contexts. In fact, whole parts of a program may be run within a mathematical context or even multiple nested contexts.
In `kmath` contexts are responsible not only for operations, but also for raw object creation and advanced features. In KMath, contexts are responsible not only for operations, but also for raw object creation and advanced features.
## Other possibilities ## Other possibilities
An obvious candidate to get more or less the same functionality is type-class feature. It allows to bind a behavior to An obvious candidate to get more or less the same functionality is the type-class, which allows one to bind a behavior to
a specific type without modifying the type itself. On a plus side, type-classes do not require explicit context a specific type without modifying the type itself. On the plus side, type-classes do not require explicit context
declaration, so the code looks cleaner. On the minus side, if there are different sets of behaviors for the same types, declaration, so the code looks cleaner. On the minus side, if there are different sets of behaviors for the same types,
it is impossible to combine them in the single module. Also, unlike type-classes, context could have parameters or even it is impossible to combine them into one module. Also, unlike type-classes, context can have parameters or even
state. For example in `kmath`, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize state. For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize
performance in case of large amount of structures. performance in case of a large amount of structures.

View File

@ -1,38 +1,40 @@
## Spaces and fields ## Spaces and fields
An obvious first choice of mathematical objects to implement in context-oriented style are algebra elements like spaces, An obvious first choice of mathematical objects to implement in a context-oriented style are algebraic elements like spaces,
rings and fields. Those are located in a `scientifik.kmath.operations.Algebra.kt` file. Alongside algebric context rings and fields. Those are located in the `scientifik.kmath.operations.Algebra.kt` file. Alongside common contexts, the file includes definitions for algebra elements like `FieldElement`. A `FieldElement` object
themselves, the file includes definitions for algebra elements such as `FieldElement`. A `FieldElement` object stores a reference to the `Field` which contains additive and multiplicative operations, meaning
stores a reference to the `Field` which contains a additive and multiplicative operations for it, meaning it has one fixed context attached and does not require explicit external context. So those `MathElements` can be operated without context:
it has one fixed context attached to it and does not require explicit external context. So those `MathElements` could be
operated without context:
```kotlin ```kotlin
val c1 = Complex(1.0, 2.0) val c1 = Complex(1.0, 2.0)
val c2 = ComplexField.i val c2 = ComplexField.i
val c3 = c1 + c2 val c3 = c1 + c2
``` ```
`ComplexField` also features special operations to mix complex numbers with real numbers like:
`ComplexField` also features special operations to mix complex and real numbers, for example:
```kotlin ```kotlin
val c1 = Complex(1.0,2.0) val c1 = Complex(1.0,2.0)
val c2 = ComplexField.run{ c1 - 1.0} //returns [re:0.0, im: 2.0] val c2 = ComplexField.run{ c1 - 1.0} // Returns: [re:0.0, im: 2.0]
val c3 = ComplexField.run{ c1 - i*2.0} val c3 = ComplexField.run{ c1 - i*2.0}
``` ```
**Note**: In theory it is possible to add behaviors directly to the context, but currently kotlin syntax does not support **Note**: In theory it is possible to add behaviors directly to the context, but currently kotlin syntax does not support
that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) for news. that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) for updates.
## Nested fields ## Nested fields
Algebra contexts allow to create more complex structures. For example, it is possible to create a `Matrix` from complex Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so:
elements like this:
```kotlin ```kotlin
val element = NDElements.create(field = ComplexField, shape = intArrayOf(2,2)){index: IntArray -> val element = NDElements.create(field = ComplexField, shape = intArrayOf(2,2)){index: IntArray ->
Complex(index[0] - index[1], index[0] + index[1]) Complex(index[0] - index[1], index[0] + index[1])
} }
``` ```
The `element` in this example is a member of `Field` of 2-d structures, each element of which is a member of its own
`ComplexField`. The important thing is that one does not need to create a special nd-structure to hold complex
numbers and implements operations on it, one need just to provide a field for its elements.
**Note**: Fields themselves do not solve problem of JVM boxing, but it is possible to solve with special contexts like The `element` in this example is a member of the `Field` of 2-d structures, each element of which is a member of its own
`ComplexField`. The important thing is one does not need to create a special n-d class to hold complex
numbers and implement operations on it, one just needs to provide a field for its elements.
**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like
`BufferSpec`. This feature is in development phase. `BufferSpec`. This feature is in development phase.

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

172
gradlew vendored Executable file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega