An experimental Python-to-C transpiler and domain specific language for embedded high-performance computing

Overview

prometeo logo by Andrea Zanelli

Travis Status PyPI version fury.io Documentation Status

This is prometeo, an experimental modeling tool for embedded high-performance computing. prometeo provides a domain specific language (DSL) based on a subset of the Python language that allows one to conveniently write scientific computing programs in a high-level language (Python itself) that can be transpiled to high-performance self-contained C code easily deployable on embedded devices.

features

  • Python compatible syntax : prometeo is a DSL embedded into the Python language. prometeo programs can be executed from the Python interpreter.
  • efficient : prometeo programs transpile to high-performance C code.
  • statically typed : prometeo uses Python's native type hints to strictly enforce static typing.
  • deterministic memory usage : a specific program structure is required and enforced through static analysis. In this way prometeo transpiled programs have a guaranteed maximum heap usage.
  • fast memory management : thanks to its static analysis, prometeo can avoid allocating and garbage-collecting memory, resulting in faster and safer execution.
  • self-contained and embeddable : unlike other similar tools and languages, prometeo targets specifically embedded applications and programs written in prometeo transpile to self-contained C code that does not require linking against the Python run-time library.

documentation (preliminary)

prometeo's documentation can be found on Read the Docs at https://prometeo.readthedocs.io/en/latest/index.html.

hello world!

A simple hello world example that shows how to either run a trivial prometeo program from Python or transpile it to C, build it and run it can be found here. The output shows the outcome of the heap usage analysis and the execution time (in this case there is not much to see :p).

performance

Since prometeo programs transpile to pure C code that calls the high performance linear algebra library BLASFEO (publication: https://arxiv.org/abs/1704.02457, code: https://github.com/giaf/blasfeo), execution time can be comparable to hand-written high-performance code. The figure below shows a comparison of the CPU time necessary to carry out a Riccati factorization using highly optimized hand-written C code with calls to BLASFEO and the ones obtained with prometeo transpiled code from this example. The computation times obtained with NumPy and Julia are added too for comparison - notice however that these last two implementations of the Riccati factorization are not as easily embeddable as the C code generated by prometeo and the hand-coded C implementation. All the benchmarks have been run on a Dell XPS-9360 equipped with an i7-7560U CPU running at 2.30 GHz (to avoid frequency fluctuations due to thermal throttling).

Moreover, prometeo can largely outperform state-of-the-art Python compilers such as Nuitka. The table below shows the CPU times obtained on a Fibonacci benchmark.

parser/compiler CPU time [s]
Python 3.7 (CPython) 11.787
Nuitka 10.039
PyPy 1.78
prometeo 0.657

PyPI installation

prometeo can be installed through PyPI with pip install prometeo-dsl. Notice that, since prometeo makes extensive use of type hints to equip Python code with static typing information, the minimum Python version required is 3.6.

manual installation

If you want to install prometeo building the sources on your local machine you can proceed as follows:

  • Run git submodule update --init to clone the submodules.
  • Run make install_shared from /prometeo/cpmt to compile and install the shared library associated with the C backend. Notice that the default installation path is /prometeo/cpmt/install .
  • You need Python 3.6. or later.
  • Optional: to keep things clean you can setup a virtual environment with virtualenv --python= .
  • Run pip install -e . from to install the Python package.

Finally, you can run the examples in /examples with pmt .py --cgen= , where the --cgen flag determines whether the code is executed by the Python interpreter or C code is generated compiled and run.

a simple example

The Python code (examples/simple_example/simple_example.py)

from prometeo import *

n : dims = 10

def main() -> int:

    A: pmat = pmat(n, n)
    for i in range(10):
        for j in range(10):
            A[i, j] = 1.0

    B: pmat = pmat(n, n)
    for i in range(10):
        B[0, i] = 2.0

    C: pmat = pmat(n, n)
    C = A * B
    pmat_print(C)
    return 0

can be run by the standard Python interpreter (version >3.6 required) and it will perform the described linear algebra operations using the command pmt simple_example.py --cgen=False. At the same time, the code can be parsed by prometeo and its abstract syntax tree (AST) analyzed in order to generate the following high-performance C code:

#include "stdlib.h"
#include "simple_example.h"
void * ___c_pmt_8_heap;
void * ___c_pmt_64_heap;
void * ___c_pmt_8_heap_head;
void * ___c_pmt_64_heap_head;

#include "prometeo.h"
int main() {
    ___c_pmt_8_heap = malloc(10000); 
    ___c_pmt_8_heap_head = ___c_pmt_8_heap;
    char * pmem_ptr = (char *)___c_pmt_8_heap;
    align_char_to(8, &pmem_ptr);
    ___c_pmt_8_heap = pmem_ptr;
    ___c_pmt_64_heap = malloc(1000000);
    ___c_pmt_64_heap_head = ___c_pmt_64_heap;
    pmem_ptr = (char *)___c_pmt_64_heap;
    align_char_to(64, &pmem_ptr);
    ___c_pmt_64_heap = pmem_ptr;
	void *callee_pmt_8_heap = ___c_pmt_8_heap;
	void *callee_pmt_64_heap = ___c_pmt_64_heap;

    struct pmat * A = c_pmt_create_pmat(n, n);
    for(int i = 0; i < 10; i++) {
        for(int j = 0; j < 10; j++) {
            c_pmt_pmat_set_el(A, i, j, 1.0);
    }

    }

    struct pmat * B = c_pmt_create_pmat(n, n);
    for(int i = 0; i < 10; i++) {
        c_pmt_pmat_set_el(B, 0, i, 2.0);
    }

    struct pmat * C = c_pmt_create_pmat(n, n);
    c_pmt_pmat_fill(C, 0.0);
    c_pmt_gemm_nn(A, B, C, C);
    c_pmt_pmat_print(C);
	___c_pmt_8_heap = callee_pmt_8_heap;
	___c_pmt_64_heap = callee_pmt_64_heap;

	free(___c_pmt_8_heap_head);
	free(___c_pmt_64_heap_head);
	return 0;
}

which relies on the high-performance linear algebra package BLASFEO. The generated code will be readily compiled and run with when running pmt simple_example.py --cgen=True.

how does it work?

Although translating a program written in a language into another with a comparable level of abstraction can be significantly easier than translating to one with a very different level of abstraction (especially if the target language is of much lower level), translating Python programs into C programs still involves a considerable abstraction gap it is not an easy task in general. Loosely speaking, the challenge lies in the necessity to reimplement features that are natively supported by the source language in the target language. In particular, when translating Python to C, the difficulty comes both from the different level of abstraction of the two languages and from the fact that the source and target language are of two very different types: Python is an interpreted, duck-typed and garbage-collevted language and C is a compiled and statically typed language.

The task of transpiling Python to C becomes even more challenging if we add the constraint that the generated C code must be efficient (even for small to medium scale computations) and deployable on embedded hardware. In fact these two requirements directly imply that the generated code cannot make use of: i) sophisticated runtime libraries, e.g., the Python runtime library, which are generally not available on embedded hardware ii) dynamic memory allocation that would make the execution slow and unreliable (exception made for memory that is allocated in a setup phase and whose size is known a priori).

Since source-to-source code transformation, or transpilation, and in particular transpilation of Python code into C code is not an unexplored realm, in the following, we mention a few existing projects that address it. In doing so, we highlight where and how they do not satisfy one of the two requirements outlined above, namely (small scale) efficiency and embeddability.

related work

Several software packages exist that address Python-to-C translation in various forms. \par In the context of high-performance computing, Numba is a just-in-time compiler for numerical functions written in Python. As such, its aim is to convert properly annotated Python functions, not entire programs, into high-performance LLVM code such that their execution can be sped up. Numba uses an internal representation of the code to be translated and performs a (potentially partial) type inference on the variables involved in order to generate LLVM code that can be called either from Python or from C/C++. In some cases, namely the ones where a complete type inference can be carried out successfully, code that does not rely on the C API can be generated (using the nopython flag). However, the emitted LLVM code would still rely on Numpy for BLAS and LAPACK operations.

Nuitka is a source-to-source compiler that can translate every Python construct into C code that links against thelibpython library and it is therefore able to transpile a large class of Python programs. In order to do so, it relies on the fact that one of the most used implementations of the Python language, namely CPython, is written in C. In fact, Nuitka generates C code that contains calls to CPython that would normally be carried out by the Python parser. Despite its attractive and general transpilation approach, it cannot be easily deployed on embedded hardware due to its intrinsic dependency on libpython. At the same time, since it maps rather closely Python constructs to their CPython implementation, a number of performance issues can be expected when it comes to small to medium scale high-performance computing. This is particularly due to the fact that operations associated with, for example, type checking, memory allocation and garbage collection that can slow down the execution are carried out by the transpiled program too.

Cython is a programming language whose goal is to facilitate writing C extensions for the Python language. In particular, it can translate (optionally) statically typed Python-like code into C code that relies on CPython. Similarly to the considerations made for Nuitka, this makes it a powerful tool whenever it is possible to rely on libpython (and when its overhead is negligible, i.e., when dealing with sufficiently large scale computations), but not in the context of interest here.

Finally, although it does not use Python as source language, we should mention that Julia too is just-in-time (and partially ahead-of-time) compiled into LLVM code. The emitted LLVM code relies however on the Julia runtime library such that considerations similar to the one made for Cython and Nuitka apply.

prometeo's transpiler

Transpilation of programs written using a restricted subset of the Python language into C programs is carried out using prometeo's transpiler. This source-to-source transformation tool analyzes abstract syntax trees (AST) associated with the source files to be transpiled in order to emit high-performance and embeddable C code. In order to do so, special rules need to be imposed on the Python code. This makes the otherwise extremely challenging task of transpiling an interpreted high-level duck-typed language into a compiled low-level statically typed one possible. In doing so, we define what is sometimes referred to as an embedded DSL in the sense the resulting language uses the syntax of a host language (Python itself) and, in prometeo's case, it can also be executed by the standard Python interpreter.

a more advanced example (Riccati factorization)

from prometeo import *

nx:  dims = 2
nu:  dims = 2
nxu: dims = nx + nu
N:   dims = 5

def main() -> int:

    # number of repetitions for timing
    nrep : int = 10000

    A: pmat = pmat(nx, nx)
    A[0,0] = 0.8
    A[0,1] = 0.1
    A[1,0] = 0.3
    A[1,1] = 0.8

    B: pmat = pmat(nx, nu)
    B[0,0] = 1.0  
    B[1,1] = 1.0

    Q: pmat = pmat(nx, nx)
    Q[0,0] = 1.0  
    Q[1,1] = 1.0

    R: pmat = pmat(nu, nu)
    R[0,0] = 1.0  
    R[1,1] = 1.0

    A: pmat = pmat(nx, nx)
    B: pmat = pmat(nx, nu)
    Q: pmat = pmat(nx, nx)
    R: pmat = pmat(nu, nu)

    RSQ: pmat = pmat(nxu, nxu)
    Lxx: pmat = pmat(nx, nx)
    M: pmat = pmat(nxu, nxu)
    w_nxu_nx: pmat = pmat(nxu, nx)
    BAt : pmat = pmat(nxu, nx)
    BA : pmat = pmat(nx, nxu)
    pmat_hcat(B, A, BA)
    pmat_tran(BA, BAt)

    RSQ[0:nu,0:nu] = R
    RSQ[nu:nu+nx,nu:nu+nx] = Q

    # array-type Riccati factorization
    for i in range(nrep):
        pmt_potrf(Q, Lxx)
        M[nu:nu+nx,nu:nu+nx] = Lxx
        for i in range(1, N):
            pmt_trmm_rlnn(Lxx, BAt, w_nxu_nx)
            pmt_syrk_ln(w_nxu_nx, w_nxu_nx, RSQ, M)
            pmt_potrf(M, M)
            Lxx[0:nx,0:nx] = M[nu:nu+nx,nu:nu+nx]

    return 0

Similarly, the code above (example/riccati/riccati_array.py) can be run by the standard Python interpreter using the command pmt riccati_array.py --cgen=False and prometeo can generate, compile and run C code using instead pmt riccati_array.py --cgen=True.

supported Python constructs

In order to be able to transpile to C, only a subset of the Python language is supported. However, non C-like features such as function overload and classes are supported by prometeo's transpiler. The adapted Riccati example (examples/riccati/riccati_mass_spring_2.py) below shows how classes can be created and used.

from prometeo import *

nm: dims = 4
nx: dims  = 2*nm
sizes: dimv = [[8,8], [8,8], [8,8], [8,8], [8,8]]
nu: dims  = nm
nxu: dims = nx + nu
N:  dims  = 5

class qp_data:
    A: List = plist(pmat, sizes)
    B: List = plist(pmat, sizes)
    Q: List = plist(pmat, sizes)
    R: List = plist(pmat, sizes)
    P: List = plist(pmat, sizes)

    fact: List = plist(pmat, sizes)

    def factorize(self) -> None:
        M: pmat = pmat(nxu, nxu)
        Mxx: pmat = pmat(nx, nx)
        L: pmat = pmat(nxu, nxu)
        Q: pmat = pmat(nx, nx)
        R: pmat = pmat(nu, nu)
        BA: pmat = pmat(nx, nxu)
        BAtP: pmat = pmat(nxu, nx)
        pmat_copy(self.Q[N-1], self.P[N-1])

        pmat_hcat(self.B[N-1], self.A[N-1], BA)
        pmat_copy(self.Q[N-1], Q)
        pmat_copy(self.R[N-1], R)
        for i in range(1, N):
            pmat_fill(BAtP, 0.0)
            pmt_gemm_tn(BA, self.P[N-i], BAtP, BAtP)

            pmat_fill(M, 0.0)
            M[0:nu,0:nu] = R
            M[nu:nu+nx,nu:nu+nx] = Q

            pmt_gemm_nn(BAtP, BA, M, M)
            pmat_fill(L, 0.0)
            pmt_potrf(M, L)

            Mxx[0:nx, 0:nx] = L[nu:nu+nx, nu:nu+nx]

            # pmat_fill(self.P[N-i-1], 0.0)
            pmt_gemm_nt(Mxx, Mxx, self.P[N-i-1], self.P[N-i-1])
            # pmat_print(self.P[N-i-1])

        return

def main() -> int:

    A: pmat = pmat(nx, nx)
    Ac11 : pmat = pmat(nm,nm)
    Ac12 : pmat = pmat(nm,nm)
    for i in range(nm):
        Ac12[i,i] = 1.0

    Ac21 : pmat = pmat(nm,nm)
    for i in range(nm):
        Ac21[i,i] = -2.0

    for i in range(nm-1):
        Ac21[i+1,i] = 1.0
        Ac21[i,i+1] = 1.0

    Ac22 : pmat = pmat(nm,nm)

    for i in range(nm):
        for j in range(nm):
            A[i,j] = Ac11[i,j]

    for i in range(nm):
        for j in range(nm):
            A[i,nm+j] = Ac12[i,j]

    for i in range(nm):
        for j in range(nm):
            A[nm+i,j] = Ac21[i,j]

    for i in range(nm):
        for j in range(nm):
            A[nm+i,nm+j] = Ac22[i,j]

    tmp : float = 0.0
    for i in range(nx):
        tmp = A[i,i]
        tmp = tmp + 1.0
        A[i,i] = tmp

    B: pmat = pmat(nx, nu)

    for i in range(nu):
        B[nm+i,i] = 1.0

    Q: pmat = pmat(nx, nx)
    for i in range(nx):
        Q[i,i] = 1.0

    R: pmat = pmat(nu, nu)
    for i in range(nu):
        R[i,i] = 1.0

    qp : qp_data = qp_data() 

    for i in range(N):
        qp.A[i] = A

    for i in range(N):
        qp.B[i] = B

    for i in range(N):
        qp.Q[i] = Q

    for i in range(N):
        qp.R[i] = R

    qp.factorize()
    
    return 0

Disclaimer: prometeo is still at a very preliminary stage and only few linear algebra operations and Python constructs are supported for the time being.

Comments
  • Add MKL as julia 1.7 dependency + minor style cleanup

    Add MKL as julia 1.7 dependency + minor style cleanup

    Hi!

    Julia 1.7 will feature a mechanism called "BLAS trampoline", which allows for loading a BLAS library at runtime (see here). This PR makes use of that and adds MKL as a dependency (plus project management/instantiation stuff). Someone running the benchmark doesn't need to have MKL installed already, it's installed during the activation of the julia project before the benchmarks are run. This will only work with julia 1.7+ though (which should be released relatively soon), so if that's a concern I can add a note somewhere saying that the benchmarks require it.

    I've also fixed the benchmarking script, since the existing version in the repo tried to run a test_riccati.jl.in file, which didn't exist. I've also made it so that the NM and NREP parameter is passed on the command line instead of hardcoding via a file.

    With this and the removal of some unnecessary (I think) copies, I get these results locally:

    riccati_benchmark

    Note that I've only run python3 run_benchmark_julia.py as well as python3 run_benchmark_numpy.py, as I don't know how to run your BLASFEO benchmarks. I suspect the remaining difference in benchmarking times is due to this, as well as my laptop not being as fast as the machine you've run your benchmarks on. Nevertheless, since Julia+MKL can match performance of prometeo/BLASFEO once the matrix size becomes large enough i.e. we're memory bound, I suspect the speedup is real.

    Cheers!

    opened by Seelengrab 6
  • Issue installing on Python 3.9.10

    Issue installing on Python 3.9.10

    Hi! I was looking forward to installing the module but came across this error while trying to install the module on Python v3.9.10:

    C:\Users\HP>py -3.9 -m pip install prometeo-dsl
    ERROR: Ignored the following versions that require a different python version: 0.0.1 Requires-Python >=3.6, <=3.9; 0.0.10 Requires-Python >=3.6, <=3.9; 0.0.2 Requires-Python >=3.6, <=3.9; 0.0.3 Requires-Python >=3.6, <=3.9; 0.0.4 Requires-Python >=3.6, <=3.9; 0.0.5 Requires-Python >=3.6, <=3.9; 0.0.6 Requires-Python >=3.6, <=3.9; 0.0.7 Requires-Python >=3.6, <=3.9; 0.0.9 Requires-Python >=3.6, <=3.9
    ERROR: Could not find a version that satisfies the requirement prometeo-dsl (from versions: none)
    ERROR: No matching distribution found for prometeo-dsl
    

    The screenshot for the same: image

    opened by Hunter2809 5
  • Question

    Question

    Hey, after reading a little bit about this project, I love it but I'm a little confused one a few parts; does it transpile to exe? Or what does it transpile the python code to so users can run? Also; would I have to write my python programs in such a way so prometeo is able to access and execute it?

    TY.

    opened by ethanperrine 3
  • How do you handle testing?

    How do you handle testing?

    Sorry if I've missed something, but is there a method you have to allow tests to run on the transpiled C to ensure it's working? (and presumably that it gives the same results as the python code, unless you've got some way of being 100% sure that is guaranteed due to your language restrictions)

    opened by nmstoker 2
  • Implement heap computation

    Implement heap computation

    This PR implements prometeo's heap computation based on the meta-information stored by the parser and Dijkstra's algorithm on the call graph that computes the worst-case heap usage. In order to do this, first, the meta-information is used to resolve the values of dims and dimv variables.

    opened by zanellia 1
  • Class and method meta-information definition

    Class and method meta-information definition

    This is part of a brainstorming with the development team on how to define meta-information structures for classes and methods within prometeo's parser. Rough draft:

    Python example

    class ClassA:
        def __init__(self):
            self.attr1 : int = 0
    
        def method1(self, arg1 : int) -> int:
            return self.attr1 + arg1
    
    class ClassB:
        def __init__(self):
            self.attr1 : int = 0
            self.attr2 : ClassA = ClassA()
    
        def method1(self, arg1 : int) -> ClassA:
            return self.attr2
    

    Meta-information:

    [
        'ClassA' : [
            'constructor_args' : 
                [('self', 'self')],
            'attributes' : 
                [('attr1', 'int', 0)],
            'methods' : [
                'method1' : 
                    'args' : 
                    [('self','self'), ('arg1', 'int')],
                    'return_type' : 'int'
            ]
        ]
    ]
    
    [
        'ClassB' : [
            'constructor_args' : 
                [('self', 'self')],
            'attributes' : 
                [('attr1', 'int', 0), ('attr2', 'ClassA', 'None')],
            'methods' : [
                'method1' : 
                    'args' : 
                    [('self','self'), ('arg1', 'int')],
                    'return_type' : 'ClassA'
            ]
        ]
    ]
    
    opened by zanellia 1
  • Towards rigorous type checking

    Towards rigorous type checking

    This PR is a first step towards improved type checking, which is currently a bit messy especially for nested attributes, BinOps and UnaryOps, Lists and so on. The PR also contains preliminary work on CasADi code-gen.

    opened by zanellia 0
  • Heap computation with instance attributes

    Heap computation with instance attributes

    replacing https://github.com/zanellia/prometeo/pull/9 - the implementation of instance attributes required quite some fixes to the heap computation machinery.

    opened by zanellia 0
  • Implement worst-case heap usage computation

    Implement worst-case heap usage computation

    This PR implements prometeo's heap computation based on the meta-information stored by the parser and Dijkstra's algorithm on the call graph that computes the worst-case heap usage. In order to do this, first, the meta-information is used to resolve the values of dims and dimv variables. In summary, the heap computation works (roughly) as follows:

    1. prometeo's parser goes through the Python code and builds a record of the constructors being defined and called: these are the only functions that give rise to memory escape in the DSL. pmat() and pvec() are the only built-in constructors, so the heap usage (64- and 8-byte aligned) is directly computed. When a constructor associated to a user class MyClass is defined the memory footprint is added to the heap usage of its __init__ method and MyClass() is registered as a constructor.

    2. after the Python code has been transpiled to C, another parser goes thorough the Python AST once more and builds a call graph, and, from the call graph, a reachability map, that describes which function scopes can be reached from every function scope - cycles are allowed, as long as there is no memory allocation in them.

    3. The worst case heap usage is computed by calculating the shortest path on a properly constructed graph (slightly modified version of the call graph) whose vertexes represent function scopes and whose edges are given by (minus) the memory allocated within each function. This graph is built such that, whenever a method that is registered as constructor at point 1 is called, the amount of memory associated with that scope is added to the caller's memory usage (i.e. accounting for memory escape)

    opened by zanellia 0
  • Meta info restructure (WIP)

    Meta info restructure (WIP)

    Addressing https://github.com/zanellia/prometeo/issues/6. The AST parser now builds an additional data structure called meta_info. For example

    from prometeo import *
    
    n : dims = 10
    
    class ClassA():
        A : pmat = pmat(n,n)
    
        def method1(self, arg1 : int) -> int:
            return 0
    
    class ClassB():
        attr1 : ClassA = ClassA()
    
    class ClassC():
        attr2 : ClassB = ClassB()
    
    def main() -> int:
        A : pmat = pmat(n,n)
        D : ClassC = ClassC()
        return 0
    

    generates

    {
       "global": {},
       "[email protected]": {
          "attr": {
             "A": "pmat"
          },
          "methods": {
             "method1": {
                "args": {
                   "arg1": "int"
                },
                "return_type": "int"
             }
          }
       },
       "[email protected]": {
          "attr": {
             "attr1": "ClassA"
          },
          "methods": {}
       },
       "[email protected]": {
          "attr": {
             "attr2": "ClassB"
          },
          "methods": {}
       }
    }
    
    opened by zanellia 0
  • Implemented tuple subscripting

    Implemented tuple subscripting

    Moving to numpy-like syntax: A[n][m] -> A[n,m].

    Additional changes:

    • dump static analysis info to JSON files
    • implement factorizations and solves (LU and Cholesky)
    • fix assignments across pmats, pvecs and scalars
    opened by zanellia 0
  • (Apple M1) OSError: dlopen(/Users/.../prometeo/prometeo/linalg/../lib/blasfeo/libblasfeo.so, 6): image not found

    (Apple M1) OSError: dlopen(/Users/.../prometeo/prometeo/linalg/../lib/blasfeo/libblasfeo.so, 6): image not found

    macOs BigSur 11.4 MacBookPro 13-inch, M1, 2020

    I cloned the repo, installed with pip install -e ., ran ipython, and tried import prometeo. I get the error:

    Python 3.8.8 (default, Apr 13 2021, 12:59:45)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.22.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: import prometeo
    ---------------------------------------------------------------------------
    OSError                                   Traceback (most recent call last)
    <ipython-input-1-371e560288bc> in <module>
    ----> 1 import prometeo
    
    ~/repos/lib/prometeo/prometeo/__init__.py in <module>
          1 from . import cgen
    ----> 2 from . import linalg
          3 from . import mem
          4 from . import auxl
          5 from . import cmdline
    
    ~/repos/lib/prometeo/prometeo/linalg/__init__.py in <module>
    ----> 1 from .pmat_blasfeo_wrapper import *
          2 from .pvec_blasfeo_wrapper import *
          3 from .pmat import *
          4 from .pvec import *
          5 from .blasfeo_wrapper import *
    
    ~/repos/lib/prometeo/prometeo/linalg/pmat_blasfeo_wrapper.py in <module>
    ----> 1 from .blasfeo_wrapper import *
          2 from ctypes import *
          3
          4
          5 bw.blasfeo_dgeex1.restype = c_double
    
    ~/repos/lib/prometeo/prometeo/linalg/blasfeo_wrapper.py in <module>
          2 import os
          3
    ----> 4 bw = CDLL(os.path.dirname(__file__) + '/../lib/blasfeo/libblasfeo.so')
          5
          6 class blasfeo_dmat(Structure):
    
    ~/opt/anaconda3/lib/python3.8/ctypes/__init__.py in __init__(self, name, mode, handle, use_errno, use_last_error, winmode)
        379
        380         if handle is None:
    --> 381             self._handle = _dlopen(self._name, mode)
        382         else:
        383             self._handle = handle
    
    OSError: dlopen(/Users/vas/repos/lib/prometeo/prometeo/linalg/../lib/blasfeo/libblasfeo.so, 6): image not found
    
    opened by vpatov 1
  • Flexible BLAS and LAPACK interface

    Flexible BLAS and LAPACK interface

    The current interface to BLAS and LAPACK routines should be made more flexible, in the sense that different levels of granularity should be accessible though the same method without adding unnecessary complexity to simple calls. Below is a draft signature for gemm suggested by @giaf:

    gemm(A[1:2,1:2], B.T, C[3:4,1:2], D=None, alpha=1.0, beta=1.0) ,

    where A, B, C and D can also be transposed through e.g. A.T and views are possible too, for example:

    gemm(A[1:2,1:2], B.T, C[3:4,1:2], D, beta=2.0).

    This is easily implementable in Python, but will require some work in prometeo's parser. In particular in the argument inspection here

    https://github.com/zanellia/prometeo/blob/f45a6347ea524164cc812fad80c9db1f4f94e17f/prometeo/cgen/code_gen_c.py#L1826)

    we'd need to do something like this:

    nargs = len(args)
    
    # extract keyword arguments
    ...
    
    # check expression in views (if any) using https://github.com/zanellia/prometeo/blob/f45a6347ea524164cc812fad80c9db1f4f94e17f/prometeo/cgen/code_gen_c.py#L244
    
    # extract and unparse views of matrix arguments (if any)
    first_index = astu.unparse(node.targets[0].slice.value.elts[0]).strip('\n')
    second_index = astu.unparse(node.targets[0].slice.value.elts[1]).strip('\n')
    
    # check for transposition (look if arg has an attribute an if it is 'T')
    
    # pass this info to a generic `process_arg()` method
    
    opened by zanellia 0
  • Improve and generalize sized type checking

    Improve and generalize sized type checking

    As of now sized type checking is carried out in a rather case-specific fashion. At some point, the typed_record (https://github.com/zanellia/prometeo/blob/master/prometeo/cgen/code_gen_c.py#L324) and the var_dim_record (https://github.com/zanellia/prometeo/blob/master/prometeo/cgen/code_gen_c.py#L328) generated during the static analysis should be merged into a single dictionary and they should support any valid sized type e.g

    n : dims = 10
    A : pmat = pmat(n,n)
    
    class ClassA():
        A : pmat = pmat(n,n)
    
    class ClassB():
        A : pmat = pmat(n,n)
        B : ClassA = ClassA()
    

    As of now 1) and 2) work fine, but to support 3) and more sophisticated user-defined sized types the code needs some restructuring.

    In particular, if we analyze

    from prometeo import *
    
    n : dims = 10
    
    class ClassA():
        A : pmat = pmat(n,n)
    
    def main() -> int:
        A : pmat = pmat(n,n)
        return 0
    

    it will result in the following typed_record:

    {
        "global": {
            "n": "dims"
        },
        "[email protected]": {
            "A": "pmat"
        },
        "globa[email protected]": {
            "A": "pmat"
        }
    }
    

    and the following var_dim_record:

    {
        "global": {},
        "[email protected]": {
            "A": [
                "n",
                "n"
            ]
        },
        "[email protected]": {
            "A": [
                "n",
                "n"
            ]
        }
    }
    
    opened by zanellia 0
  • Milestones for minimal complete DSL

    Milestones for minimal complete DSL

    High-priority

    • [ ] Support for basic types: int, double, pmat and pvec
      • [x] declaration of variables of supported types
      • [x] specification of function arguments of supported types
      • [x] simple operations ('+', '-', '*', '/') on int and double types
    • [ ] Support for high-level basic linear algebra operations on pmat variables
      • [x] C = A + B
      • [x] C = A - B
      • [x] C = A * B
      • [x] C = A\B
    • [x] Support for subscripting of pmat variables
      • [x] get value (val = A[i,j])
      • [x] set value (A[i,j] = val)
    • [x] Support for functions calls
    • [x] Support for structures
      • [x] structure declaration
      • [x] structure access
    • [ ] Support of arrays of all supported types
      • [x] array of pmat declaration through Python Lists
      • [x] array of other supported types declaration through Python Lists
      • [x] array of structures declaration through Python Lists
      • [x] accessing and setting arrays of pmats
    • [x] Support for function definitions (no mem escape)
    • [x] Extend AST parser to keep track of heap usage
    • [ ] AST-based verification of user code
    • [x] Unit testing

    Low-priority/long-term

    • [x] Support for simple classes
    • [ ] Support for CasADi functions

    Improvements

    • [x] Remove dims from type hints in declarations (keep only in function signature)
    • [x] Add linear algebra routines with explicit return
    • [x] Add support for slicing
    opened by zanellia 0
Releases(0.0.11)
Owner
Andrea Zanelli
Postdoc at the Institute for Dynamic Systems and Control, ETH Zurich - numerical optimization, model predictive control
Andrea Zanelli
Replit theme sync; Github theme sync but in Replit.

This is a Replit theme sync, basically meaning that it keeps track of the current time (which may need to be edited later on), and if the time passes morning, afternoon, etc, the theme switches. The

Glitch 8 Jun 25, 2022
This repository contains a lot of short scripting programs implemented both in Python (Flask) and TypeScript (NodeJS).

fast-scripts This repository contains a lot of short scripting programs implemented both in Python (Flask) and TypeScript (NodeJS). In python These wi

Nahum Maurice 3 Dec 10, 2022
A carrot-based color palette you didn't know you needed.

A package to produce a carrot-inspired color palette for python/matplotlib. Install: pip install carrotColors Update: pip install --upgrade carrotColo

10 Sep 28, 2021
Submission to the HEAR2021 Challenge

Submission to the HEAR 2021 Challenge For model evaluation, python=3.8 and cuda10.2 with cudnn7.6.5 have been tested. The work uses a mixed supervised

Heinrich Dinkel 10 Dec 08, 2022
A simple weather app.

keather A simple weather app. This is currently not finished. Dependencies: yay -S python-beautifulsoup4 tk

1 Jan 09, 2022
About A python based Apple Quicktime protocol,you can record audio and video from real iOS devices

介绍 本应用程序使用 python 实现,可以通过 USB 连接 iOS 设备进行屏幕共享 高帧率(30〜60fps) 高画质 低延迟(200ms) 非侵入性 支持多设备并行 Mac OSX 安装 python =3.7 brew install libusb pkg-config 如需使用 g

YueC 124 Nov 30, 2022
because rico hates uuid's

terrible-uuid-lambda because rico hates uuid's sub 200ms response times! Try it out here: https://api.mathisvaneetvelde.com/uuid https://api.mathisvan

Mathis Van Eetvelde 2 Feb 15, 2022
Open source home automation that puts local control and privacy first

Home Assistant Open source home automation that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiast

Home Assistant 57k Jan 02, 2023
Shell scripts made simple 🐚

zxpy Shell scripts made simple 🐚 Inspired by Google's zx, but made much simpler and more accessible using Python. Rationale Bash is cool, and it's ex

Tushar Sadhwani 492 Dec 27, 2022
Coinloggr - A learning resource and social platform for the coin collecting community

Coinloggr A learning resource and social platform for the coin collecting commun

John Galiszewski 1 Jan 10, 2022
Multi-Process / Censorship Detection

Multi-Process / Censorship Detection

Baris Dincer 2 Dec 22, 2021
Coded in Python 3 - I make for education, easily clone simple website.

Simple Website Cloner - Single Page Coded in Python 3 - I make for education, easily clone simple website. How to use ? Install Python 3 first. Instal

Phạm Đức Thanh 2 Jan 13, 2022
Project repository of Apache Airflow, deployed on Docker in Amazon EC2 via GitLab.

Airflow on Docker in EC2 + GitLab's CI/CD Personal project for simple data pipeline using Airflow. Airflow will be installed inside Docker container,

Ammar Chalifah 13 Nov 29, 2022
HogwartsRegister - A Hogwarts Register With Python

A Hogwarts Register Installation download code git clone https://github.com/haor

0 Feb 12, 2022
Simple dotfile pre-processor with a per-file configuration

ix (eeks) Simple dotfile pre-processor with a per-file configuration Summary (TL;DR) ix.py is all you need config is an ini file. files to be processe

Poly 12 Dec 16, 2021
Web站点选优工具 - 优化GitHub的打开速度、高效Clone

QWebSiteOptimizer - Web站点速度选优工具 在访问GitHub等网站时,DNS解析到的IP地址可能并不是最快,过慢的节点会严重影响我们的访问情况,故制作出这样的工具来进一步优化网络质量。 由于该方案并非为VPN等方式进行的速度优化,以下几点需要您注意: 后续访问对应网站时仍可能需

QPT Family 15 May 01, 2022
AMTIO aka All My Tools in One

AMTIO AMTIO aka All My Tools In One. I plan to put a bunch of my tools in this one repo since im too lazy to make one big tool. Installation git clone

osintcat 3 Jul 29, 2021
Simulation simplifiée du fonctionnement du protocole RIP

ProjetRIPlay v2 Simulation simplifiée du fonctionnement du protocole RIP par Eric Buonocore le 18/01/2022 Sur la base de l'exercice 5 du sujet zéro du

Eric Buonocore 2 Feb 15, 2022
Cisco IOS-XE Operations Program. Shows operational data using restconf and yang

XE-Ops View operational and config data from devices running Cisco IOS-XE software. NoteS The build folder is the latest build. All other files are fo

18 Jul 23, 2022
A curated list of awesome things related to Pydantic! 🌪️

Awesome Pydantic A curated list of awesome things related to Pydantic. These packages have not been vetted or approved by the pydantic team. Feel free

Marcelo Trylesinski 186 Jan 05, 2023