Giter Site home page Giter Site logo

bjodah / pyodesys Goto Github PK

View Code? Open in Web Editor NEW
91.0 9.0 7.0 10.54 MB

∫ Straightforward numerical integration of systems of ordinary differential equations

License: BSD 2-Clause "Simplified" License

Python 74.95% Shell 4.41% JavaScript 0.92% C++ 8.00% Jupyter Notebook 3.32% TeX 0.50% Dockerfile 0.31% Cython 7.59%
ordinary-differential-equations numerical-codes code-generation symbolic-manipulation sympy initial-value-problem

pyodesys's Introduction

pyodesys

Build status on Woodpecker CI

PyPI version

License

coverage

Journal of Open Source Software DOI

pyodesys provides a straightforward way of numerically integrating systems of ordinary differential equations (initial value problems). It unifies the interface of several libraries for performing the numerical integration as well as several libraries for symbolic representation. It also provides a convenience class for representing and integrating ODE systems defined by symbolic expressions, e.g. SymPy expressions. This allows the user to write concise code and rely on pyodesys to handle the subtle differences between libraries.

The numerical integration is performed using either:

Note that implicit steppers require a user supplied callback for calculating the Jacobian. pyodesys.SymbolicSys derives the Jacobian automatically.

The symbolic representation is usually in the form of SymPy expressions, but the user may choose another symbolic back-end (see sym).

When performance is of utmost importance, e.g. in model fitting where results are needed for a large set of initial conditions and parameters, the user may transparently rely on compiled native code (classes in pyodesys.native.native_sys can generate optimal C++ code). The major benefit is that there is no need to manually rewrite the corresponding expressions in another programming language.

Documentation

Auto-generated API documentation for latest stable release is found here: https://bjodah.github.io/pyodesys/latest (and the development version for the current master branch is found here: http://artifacts.bjodah.se/pyodesys/branches/master/html).

Installation

Simplest way to install pyodesys and its (optional) dependencies is to use the conda package manager:

$ conda install -c bjodah pyodesys pytest
$ python -m pytest --pyargs pyodesys

Optional dependencies

If you used conda to install pyodesys you can skip this section. But if you use pip you may want to know that the default installation of pyodesys only requires SciPy:

$ pip install pyodesys
$ pytest --pyargs pyodesys -rs

The above command should finish without errors but with some skipped tests. The reason for why some tests are skipped should be because missing optional solvers. To install the optional solvers you will first need to install third party libraries for the solvers and then their python bindings. The 3rd party requirements are as follows:

if you want to see what packages need to be installed on a Debian based system you may look at this Dockerfile.

If you manage to install all three external libraries you may install pyodesys with the option "all":

$ pip install pyodesys[all]
$ pytest --pyargs pyodesys -rs

now there should be no skipped tests. If you try to install pyodesys on a machine where you do not have root permissions you may find the flag --user helpful when using pip. Also if there are multiple versions of python installed you may want to invoke python for an explicit version of python, e.g.:

$ python3.6 -m pip install --user pyodesys[all]

see setup.py for the exact list of requirements.

Using Docker

If you have Docker installed, you may use it to host a jupyter notebook server:

$ ./scripts/host-jupyter-using-docker.sh . 8888

the first time you run the command some dependencies will be downloaded. When the installation is complete there will be a link visible which you can open in your browser. You can also run the test suite using the same docker-image:

$ ./scripts/host-jupyter-using-docker.sh . 0

there will be one skipped test (due to symengine missing in this pip installed environment) and quite a few instances of RuntimeWarning.

Examples

The classic van der Pol oscillator (see examples/van_der_pol.py)

>>> from pyodesys.symbolic import SymbolicSys
>>> def f(t, y, p):
...     return [y[1], -y[0] + p[0]*y[1]*(1 - y[0]**2)]
... 
>>> odesys = SymbolicSys.from_callback(f, 2, 1)
>>> xout, yout, info = odesys.integrate(10, [1, 0], [1], integrator='odeint', nsteps=1000)
>>> _ = odesys.plot_result()
>>> import matplotlib.pyplot as plt; plt.show()  # doctest: +SKIP

image

If the expression contains transcendental functions you will need to provide a backend keyword argument:

>>> import math
>>> def f(x, y, p, backend=math):
...     return [backend.exp(-p[0]*y[0])]  # analytic: y(x) := ln(kx + kc)/k
... 
>>> odesys = SymbolicSys.from_callback(f, 1, 1)
>>> y0, k = -1, 3
>>> xout, yout, info = odesys.integrate(5, [y0], [k], integrator='cvode', method='bdf')
>>> _ = odesys.plot_result()
>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> c = 1./k*math.exp(k*y0)  # integration constant
>>> _ = plt.plot(xout, np.log(k*(xout+c))/k, '--', linewidth=2, alpha=.5, label='analytic')
>>> _ = plt.legend(loc='best'); plt.show()  # doctest: +SKIP

image

If you already have symbolic expressions created using e.g. SymPy you can create your system from those:

>>> import sympy as sp
>>> t, u, v, k  = sp.symbols('t u v k')
>>> dudt = v
>>> dvdt = -k*u  # differential equations for a harmonic oscillator
>>> odesys = SymbolicSys([(u, dudt), (v, dvdt)], t, [k])
>>> result = odesys.integrate(7, {u: 2, v: 0}, {k: 3}, integrator='gsl', method='rk8pd', atol=1e-11, rtol=1e-12)
>>> _ = plt.subplot(1, 2, 1)
>>> _ = result.plot()
>>> _ = plt.subplot(1, 2, 2)
>>> _ = plt.plot(result.xout, 2*np.cos(result.xout*3**0.5) - result.yout[:, 0])
>>> plt.show()  # doctest: +SKIP

image

You can also refer to the dependent variables by name instead of index:

>>> odesys = SymbolicSys.from_callback(
...     lambda t, y, p: {
...         'x': -p['a']*y['x'],
...         'y': -p['b']*y['y'] + p['a']*y['x'],
...         'z': p['b']*y['y']
...     }, names='xyz', param_names='ab', dep_by_name=True, par_by_name=True)
... 
>>> t, ic, pars = [42, 43, 44], {'x': 7, 'y': 5, 'z': 3}, {'a': [11, 17, 19], 'b': 13}
>>> for r, a in zip(odesys.integrate(t, ic, pars, integrator='cvode'), pars['a']):
...     assert np.allclose(r.named_dep('x'), 7*np.exp(-a*(r.xout - r.xout[0])))
...     print('%.2f ms ' % (r.info['time_cpu']*1e3))  # doctest: +SKIP
... 
10.54 ms
11.55 ms
11.06 ms

Note how we generated a list of results for each value of the parameter a. When using a class from pyodesys.native.native_sys those integrations are run in separate threads (bag of tasks parallelism):

>>> from pyodesys.native import native_sys
>>> native = native_sys['cvode'].from_other(odesys)
>>> for r, a in zip(native.integrate(t, ic, pars), pars['a']):
...     assert np.allclose(r.named_dep('x'), 7*np.exp(-a*(r.xout - r.xout[0])))
...     print('%.2f ms ' % (r.info['time_cpu']*1e3))  # doctest: +SKIP
... 
0.42 ms
0.43 ms
0.42 ms

For this small example we see a 20x (serial) speedup by using native code. Bigger systems often see 100x speedup. Since the latter is run in parallel the (wall clock) time spent waiting for the results is in practice further reduced by a factor equal to the number of cores of your CPU (number of threads used is set by the environment variable ANYODE_NUM_THREADS).

For further examples, see examples/, and rendered jupyter notebooks here: http://artifacts.bjodah.se/pyodesys/branches/master/examples

Run notebooks using binder

Using only a web-browser (and an internet connection) it is possible to explore the notebooks here: (by the courtesy of the people behind mybinder)

Binder

Citing

If you make use of pyodesys in e.g. academic work you may cite the following peer-reviewed publication:

Journal of Open Source Software DOI

Depending on what underlying solver you are using you should also cite the appropriate paper (you can look at the list of references in the JOSS article). If you need to reference, in addition to the paper, a specific point version of pyodesys (for e.g. reproducibility) you can get per-version DOIs from the zenodo archive:

Zenodo DOI

Licenseing

The source code is Open Source and is released under the simplified 2-clause BSD license. See LICENSE for further details.

Contributing

Contributors are welcome to suggest improvements at https://github.com/bjodah/pyodesys (see further details here).

Author

Original author: Björn I. Dahlgren (gmail address: bjodah). See file AUTHORS for a list of all authors.

pyodesys's People

Contributors

bjodah avatar slayoo avatar smsaladi avatar spcornelius avatar stephweissm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyodesys's Issues

Tests fail due to a missing extra: pycvodes

___________________________________________________________ ERROR collecting pyodesys/native/tests/test_odeint.py ___________________________________________________________
ImportError while importing test module '/usr/ports/math/py-pyodesys/work-py27/pyodesys-0.12.3/pyodesys/native/tests/test_odeint.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
pyodesys/native/__init__.py:14: in <module>
    from .cvode import NativeCvodeSys
pyodesys/native/cvode.py:18: in <module>
    class NativeCvodeCode(_NativeCodeBase):
pyodesys/native/cvode.py:22: in NativeCvodeCode
    _realtype = _config.env.get('REAL_TYPE', 'double')
pyodesys/util.py:272: in __getattribute__
    raise self._exc  # ImportError("Failed to import %s" % self._modname)
E   ImportError: No module named pycvodes
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 3 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Extra dependencies are optional, and should only cause test warnings.

new installation, but don't pass the test

============================= test session starts ==============================
platform linux2 -- Python 2.7.15, pytest-4.4.2, py-1.8.0, pluggy-0.11.0
rootdir: /home/nightwing
collected 266 items

anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/native/tests/test_cvode.py F [ 0%]
FFFFFFFFFFFFFFFFFFFxFFFFFFFFFFFF [ 12%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/native/tests/test_gsl.py F [ 12%]
FFFFFFFFFFFFFF [ 18%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/native/tests/test_odeint.py F [ 18%]
FFFFFFFFFFx [ 22%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/tests/test_core.py F [ 22%]
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFsssF [ 35%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/tests/test_plotting.py F [ 36%]
F [ 36%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/tests/test_results.py F [ 36%]
FF [ 37%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/tests/test_robertson.py F [ 37%]
FFFFFFFFF [ 41%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/tests/test_symbolic.py . [ 41%]
F.FFFFFFF.FFFFFF..FF....FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF [ 68%]
FFFFFFFFFFFFFFFF.FFFFFF..FFFFF.FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.. [ 95%]
ssFF..FFF [ 99%]
anaconda3/envs/pyodesys/lib/python2.7/site-packages/pyodesys/tests/test_util.py F [ 99%]
. [100%]

=================================== FAILURES ===================================
________________________________ test_NativeSys ________________________________

(PS: too long to be put here.....)

== 241 failed, 18 passed, 5 skipped, 2 xfailed, 17 warnings in 75.23 seconds ===

Invariants

SymbolicSys.invariants and SymbolicSys.linear_invariants where the latter is a non-symbolic matrix.

Native odesys ignores provided parameters if it is based on SymbolicSys created by chempy

I tried your example on native odesys. Providing different parameters leads to different concentrations as it should.

Now I noticed that if I construct the odesys using chempy, the results stay the same even if I change the parameters:

from chempy import ReactionSystem  # The rate constants below are arbitrary
from chempy.kinetics.ode import get_odesys
from collections import defaultdict
import numpy as np

from pyodesys.native import native_sys

rsys = ReactionSystem.from_string("""2 Fe+2 + H2O2 -> 2 Fe+3 + 2 OH-; 42
    2 Fe+3 + H2O2 -> 2 Fe+2 + O2 + 2 H+; 17
    H+ + OH- -> H2O; 1e10
    H2O -> H+ + OH-; 1e-4""")  # "[H2O]" = 1.0 (actually 55.4 at RT)
chempy_odesys, extra = get_odesys(rsys)

tout = sorted(np.concatenate((np.linspace(0, 23), np.logspace(-8, 1))))
c0 = defaultdict(float, {'Fe+2': 0.05, 'H2O2': 0.1, 'H2O': 1.0, 'H+': 1e-2, 'OH-': 1e-12})

print('Results from symbolic odesys')
result = chempy_odesys.integrate(tout, c0, atol=1e-12, rtol=1e-14)
np.array(result.at(tout))[-1,0]

chempy_native = native_sys['cvode'].from_other(chempy_odesys)

print('Results from native odesys without providing parameters')
result_chempy_native = chempy_native.integrate(tout, c0)
np.array(result_chempy_native.at(tout))[-1,0]

chempy_org_params = rsys.params()

print('Results from native odesys providing old parameters: ' + str(chempy_org_params))
result_chempy_native_org_params = chempy_native.integrate(tout, c0, chempy_org_params)
np.array(result_chempy_native_org_params.at(tout))[-1,0]

chempy_new_params = [4.2, 1.7, 1e5, 1e-2]
print('Results from native odesys providing new parameters: ' + str(chempy_new_params))
result_chempy_native_new_params = chempy_native.integrate(tout, c0, chempy_new_params)
np.array(result_chempy_native_new_params.at(tout))[-1,0]

print(chempy_org_params)
print(chempy_new_params)
print(np.array(chempy_org_params) / np.array(chempy_new_params))

The output:

Results from symbolic odesys

array([1.94487014e-02, 3.05512986e-02, 7.38097945e-12, 1.05023516e+00,
       4.44891879e-02, 2.01175814e-02, 2.05512986e-02])

Results from native odesys without providing parameters

INFO:pyodesys.native._base:In "/tmp/tmpGbkXsw_pycodeexport_pyodesys_NativeCvodeCode", executing:
"/usr/bin/g++ -c -std=c++11 -Wall -Wextra -fPIC -O2 -ffast-math -funroll-loops -fopenmp -o ./odesys_anyode.o -I/home/niklas/anaconda2/lib/python2.7/site-packages/numpy/core/include -I/home/niklas/anaconda2/lib/python2.7/site-packages/pyodesys/native/sources -I/home/niklas/anaconda2/lib/python2.7/site-packages/pycvodes/include odesys_anyode.cpp"
INFO:pyodesys.native._base:In "/tmp/tmpGbkXsw_pycodeexport_pyodesys_NativeCvodeCode", executing:
"/usr/bin/g++ -pthread -shared -std=c++11 -Wall -Wextra -fPIC -O2 -ffast-math -funroll-loops -fopenmp -o /tmp/tmpGbkXsw_pycodeexport_pyodesys_NativeCvodeCode/_cvode_wrapper.so -I/home/niklas/anaconda2/lib/python2.7/site-packages/numpy/core/include -I/home/niklas/anaconda2/lib/python2.7/site-packages/pyodesys/native/sources -I/home/niklas/anaconda2/lib/python2.7/site-packages/pycvodes/include odesys_anyode.o _cvode_wrapper.o -lsundials_cvodes -lsundials_nvecserial -lsundials_sunlinsollapackdense -lsundials_sunlinsollapackband -lopenblas -lpython2.7"

array([ 1.94486898e-02,  3.05513102e-02, -2.05513102e-02,  1.07078646e+00,
        4.44891934e-02,  2.01175757e-02, -7.42631650e-12])

Results from native odesys providing old parameters: [42, 17, 10000000000.0, 0.0001]

array([ 1.94486898e-02,  3.05513102e-02, -2.05513102e-02,  1.07078646e+00,
        4.44891934e-02,  2.01175757e-02, -7.42631650e-12])

Results from native odesys providing new parameters: [4.2, 1.7, 100000.0, 0.01]

array([ 1.94486898e-02,  3.05513102e-02, -2.05513102e-02,  1.07078646e+00,
        4.44891934e-02,  2.01175757e-02, -7.42631650e-12])

[42, 17, 10000000000.0, 0.0001]
[4.2, 1.7, 100000.0, 0.01]
[1.e+01 1.e+01 1.e+05 1.e-02]

There are minor numerical differences between the results from the symbolic odesys and the native one. In the latter, the ordering of species is slightly different and there are some negative concentrations, though. Can their absolute values be safely used or this there something wrong with them?
The provided parameters change nothing, though. Is there a way to make this work? Thanks in advance!

chempy 0.6.15
pyodesys 0.11.17
python 2.7.15

same behaviour with
chempy 0.7.6
pyodesys 0.12.4

notebook>=5.7.8 requirement in setup.py makes packages that depend on chempy unusable on Google Colab

Google's Colab platform offers Jupyter execution in the cloud with GPU support, etc. You can do pip install there, but it is not possible to change the version of pre-installed notebook package. pyodesys requires notebook>=5.7.8 while Colab uses 5.3.1.

Now, current chempy requires pyodesys>=0.14.0 which makes it unusable on Colab, and same for any package that has "chempy" within its dependencies. The workaround is to do:

pip install chempy==0.7.10 pyodesys==0.13.0 notebook==5.3.1

on Colab, and that is what we will do in PySDM-examples. Given that we get 1.5-year old chempy as a side-effect of requiring a particular version of notebook in pyodesys, it sounds as a mishap :)

Is notebook>=5.7.8 really a strong requirement here?

JOSS: Issues installing

@bjodah I'm having some issues installing pyodesys for the JOSS review:

First, let me note that installing the main package via conda worked without a hitch, pip not so much (but that's a more difficult nut to crack). However:

  1. There needs to be a list of all dependencies that are needed to run tests / examples / etc. A lot of this can be inferred from either the setup.py or the other optional packages, but I tried that route and I'm still running into errors on tests / examples (more on this later). Preferably this list would be the docs, and there would be a link in the install section along the lines of "Optional Dependencies...". Even if this links to the various subpackages (e.g. pygslodeiv2) which then tell you how to install themselves, that would be an improvement.

  2. This list needs to include any non-python packages required such that a pip install will be possible.
    Conda is obviously an easier choice, but if you're going to offer pip installation I need to the base packages required. Again using pygslodeiv2 as an example, it's not immediately obvious where GSL should be installed to (other than "default" locations?). Or for odeint do I need Boost? ode-int itself?

  3. Even with (I think) all the sub-dependencies installed, most of the tests skip and the examples give erros. My conda environment is here

e.g.: my test output:

pyodesys/pyodesys/native/tests/test_cvode.py sssssssssssssssssssssssssssss [ 11%]
pyodesys/pyodesys/native/tests/test_gsl.py sssssFsssssssss [ 16%]
pyodesys/pyodesys/native/tests/test_odeint.py ssssFsssssss [ 21%]
pyodesys/pyodesys/tests/test_core.py s.ssssssss....s.....s..s..s..ssss. [ 34%]
pyodesys/pyodesys/tests/test_plotting.py ss [ 35%]
pyodesys/pyodesys/tests/test_results.py ..s [ 36%]
pyodesys/pyodesys/tests/test_robertson.py ssssssssss [ 40%]
pyodesys/pyodesys/tests/test_symbolic.py ....ssssssssss.................ssssssssssssssssssssssssssssssssssssssssss...sssssssssss.sss.s.s....ss..ssssssssssssssss [ 86%]
sssssssssssssssssssssss.ssssssssss [ 99%]
pyodesys/pyodesys/tests/test_util.py ..

Or running chemical_kinetics.ipynb:

~/miniconda3/envs/pyodesys/lib/python3.6/site-packages/pycvodes/init.py in ()
7 import numpy as np
8
----> 9 from ._cvodes import adaptive, predefined, requires_jac, steppers, fpes
10 from ._util import _check_callable, _check_indexing
11 from ._release import version

ImportError: libsundials_cvodes.so.2: cannot open shared object file: No such file or directory

edit: link back to joss review:
openjournals/joss-reviews#490 (comment)

Result object

xout, yout, info = result = odesys.integrate(xend, y0, params)
result.plot(names=('A', 'C'))

Roadmap

  • Support for DAE systems (through IDAS from sundials)
  • OdeSys.solve_bvp method (and an alias for solve_ivp = integrate)
  • time integration through PETSc (Python interface or natively)
  • support for method-of-lines discretized PDEs
  • code-generation for sensitivity analysis

Generic types support in native code

The most recent updates to anyode support generic types for reals and indices, which has the most relevance for cvodes. Although the same .cpp template is used for native code generation regardless of the integrator, and the different integration packages may use different types, this could nonetheless easily be implemented by, for example, having static variables within each Native*Sys class indicating typenames to be filled in by mako.

ValueError: cannot create object arrays from iterator

The following code snippet raises a ValueError:

import numpy as np
from pyodesys.symbolic import SymbolicSys

def rhs(f, g, u, c, k):
    """
    Make the rhs for coupled, controlled oscillators.
    .. math::
        \dot{x}_i = f(x_i) + \sum_j c_{ij} g(x_i, x_j) + k_iu(x_1,\ldots,x_n)

    :param f: onsite dynamics
    :param g: coupling function
    :param u: control function
    :param c: coupling matrix
    :param k: control switch
    :return: rhs
    """
    def inner(t, y, p):
        coupling = (sum(cij*g(xi, xj) for cij, xj in zip(ci,y)) for ci, xi in zip(c,y))
        coupling = np.fromiter(coupling, y.dtype)
        return f(y) + coupling + k*u(y)
    return inner

n = 3
f = rhs(lambda x: -x, lambda x, y: (x-y)**2, lambda x: 0, np.eye(n), np.zeros(n))

odesys = SymbolicSys.from_callback(f, n)

It works just fine if you use a list expression and coupling = np.array(coupling) tough.

subroutine that can give the result of each step of Bulirsch_stoer

is it possible to get the subroutine which can give the result of each step of Bulirsch_stoer solver? I would like to use pyodesys to help me solve odes by using Bulirsch_stoer method, and after each step, we need to use current results to update our odes. Do you think where can i find that subroutine?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.