├── bot ├── runme.sh ├── thumbsup.png ├── plot-example.txt ├── colored.py ├── teleplot.py ├── telecling.py └── cxxbot.py ├── logo.png ├── stellar-logo.png ├── install-from-spack.sh ├── notebk.sh ├── alternatives.sh ├── make.sh ├── limits.patch ├── docker-compose.build.yml ├── docker-compose.yml ├── char.patch ├── noexcept.patch ├── find.py ├── is_expr.py ├── docker-compose.server.yml ├── pipes3.py ├── mkuser.py ├── nb.py ├── startup.sh ├── Pipe.hpp ├── teleplot.hpp ├── notebooks ├── Lecture3.ipynb ├── Lecture1.ipynb ├── pyclingexample.ipynb ├── Lecture2.ipynb ├── HPX_Training.ipynb └── py11demo.ipynb ├── vector_pack_type.hpp ├── login.html ├── README.md ├── jup-config.py ├── pipes1.py ├── login2.html ├── error.html ├── Augment_Kernel.hpp ├── cling.py ├── hpxcxx ├── run_hpx.cpp ├── Kernel.cpp ├── Dockerfile ├── Dockerfile.ubuntu ├── cin.py └── py11.py /bot/runme.sh: -------------------------------------------------------------------------------- 1 | rm -f nohup.out 2 | nohup watch python3 cxxbot.py & 3 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stevenrbrandt/CxxExplorer/HEAD/logo.png -------------------------------------------------------------------------------- /bot/thumbsup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stevenrbrandt/CxxExplorer/HEAD/bot/thumbsup.png -------------------------------------------------------------------------------- /stellar-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stevenrbrandt/CxxExplorer/HEAD/stellar-logo.png -------------------------------------------------------------------------------- /bot/plot-example.txt: -------------------------------------------------------------------------------- 1 | std::cout << "{ \"datasets\":[{\"name\":\"fig1\", \"data\":[[1,1.2],[2,1.1],[3,1.2],[4,1.1]]}]}" << std::endl; 2 | -------------------------------------------------------------------------------- /install-from-spack.sh: -------------------------------------------------------------------------------- 1 | cd /usr 2 | git clone https://github.com/spack/spack.git 3 | source /usr/spack/share/spack/setup-env.sh 4 | spack install gcc@${GCC_VER} 5 | spack load gcc@${GCC_VER} 6 | spack compiler find 7 | spack gc -y 8 | -------------------------------------------------------------------------------- /notebk.sh: -------------------------------------------------------------------------------- 1 | echo "Starting notebook" 2 | echo jupyter notebook --allow-root --ip=0.0.0.0 --port=${PORT} --no-browser --NotebookApp.token="${SECRET_TOKEN}" 3 | jupyter notebook --allow-root --ip=0.0.0.0 --port=${PORT} --no-browser --NotebookApp.token="${SECRET_TOKEN}" 4 | -------------------------------------------------------------------------------- /alternatives.sh: -------------------------------------------------------------------------------- 1 | source /usr/spack/share/spack/setup-env.sh 2 | spack load gcc 3 | update-alternatives --install /usr/bin/cc cc $(which gcc) 1 4 | rm -f /usr/bin/c++ 5 | ln -s /etc/alternatives/c++ /usr/bin/c++ 6 | update-alternatives --install /usr/bin/c++ c++ $(which g++) 1 7 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | export NCPUS=$(lscpu|grep '^CPU.s.:'|cut -d: -f2) 2 | export BUILD_CPUS=2 #$(($NCPUS/2)) 3 | make VERBOSE=yes -j $BUILD_CPUS install 2>&1 | tee make.out 4 | cd /usr/install/cling 5 | find . -type f -a \( -name \*.o -o -name \*.cmake -o -name \*.cpp -o -name \*.h -name \*.c \) | xargs rm -f 6 | which cling 7 | -------------------------------------------------------------------------------- /limits.patch: -------------------------------------------------------------------------------- 1 | diff --git a/utils/benchmark/src/benchmark_register.h b/utils/benchmark/src/benchmark_register.h 2 | index 0705e219..6001fb8e 100644 3 | --- a/utils/benchmark/src/benchmark_register.h 4 | +++ b/utils/benchmark/src/benchmark_register.h 5 | @@ -2,6 +2,7 @@ 6 | #define BENCHMARK_REGISTER_H 7 | 8 | #include 9 | +#include 10 | 11 | #include "check.h" 12 | 13 | -------------------------------------------------------------------------------- /docker-compose.build.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | # Use this file to build the C++Explorer instead of downloading it. 3 | # docker-compose -f docker-compose.build.yml build --pull 4 | 5 | services: 6 | 7 | cxxex-src-workspace: 8 | build: 9 | args: 10 | CPUS: 2 11 | BUILD_TYPE: Release 12 | context: . 13 | dockerfile: Dockerfile.ubuntu 14 | image: stevenrbrandt/cxxex-src 15 | container_name: cxxex-src-nbk 16 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | volumes: 4 | # Provide persistent storage 5 | nbk_home: 6 | 7 | services: 8 | 9 | cxxex-src-workspace: 10 | image: stevenrbrandt/cxxex-src 11 | container_name: cxxex-src-nbk 12 | user: jovyan 13 | entrypoint: bash /notebooks/notebk.sh 14 | #entrypoint: sleep infinity 15 | environment: 16 | - "PORT=8004" 17 | - "SECRET_TOKEN=spoon" 18 | ports: 19 | - "9080:8004" 20 | #volumes: 21 | # - nbk_home:/home 22 | -------------------------------------------------------------------------------- /bot/colored.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def not_colored(a,_): 4 | return a 5 | 6 | installed = None 7 | 8 | try: 9 | from termcolor import colored 10 | installed = True 11 | except: 12 | colored = not_colored 13 | installed = False 14 | 15 | if hasattr(sys.stdout,"isatty"): 16 | is_tty = sys.stdout.isatty() 17 | else: 18 | is_tty = False 19 | 20 | is_jupyter = type(sys.stdout).__name__ == 'OutStream' and type(sys.stdout).__module__ == 'ipykernel.iostream' 21 | if (not is_tty) and (not is_jupyter): 22 | colored = not_colored 23 | 24 | if __name__ == "__main__": 25 | if installed: 26 | print(colored("Colored was installed","green")) 27 | else: 28 | print("Colored was NOT installed") 29 | -------------------------------------------------------------------------------- /char.patch: -------------------------------------------------------------------------------- 1 | diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h 2 | index da02250b..f681d038 100644 3 | --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h 4 | +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h 5 | @@ -713,7 +713,7 @@ private: 6 | 7 | uint32_t getTrampolineSize() const { return RemoteTrampolineSize; } 8 | 9 | - Expected> readMem(char *Dst, JITTargetAddress Src, 10 | + Expected> readMem(char *Dst, JITTargetAddress Src, 11 | uint64_t Size) { 12 | // Check for an 'out-of-band' error, e.g. from an MM destructor. 13 | if (ExistingError) 14 | -------------------------------------------------------------------------------- /noexcept.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/Interpreter/ForwardDeclPrinter.cpp b/lib/Interpreter/ForwardDeclPrinter.cpp 2 | index 9e50b16..cfecd74 100644 3 | --- a/lib/Interpreter/ForwardDeclPrinter.cpp 4 | +++ b/lib/Interpreter/ForwardDeclPrinter.cpp 5 | @@ -490,6 +490,7 @@ namespace cling { 6 | Proto += ")"; 7 | } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { 8 | Proto += " noexcept"; 9 | +#if 0 10 | if (isComputedNoexcept(FT->getExceptionSpecType())) { 11 | Proto += "("; 12 | llvm::raw_string_ostream EOut(Proto); 13 | @@ -501,6 +502,7 @@ namespace cling { 14 | //Print was already being called earlier above 15 | Proto += ")"; 16 | } 17 | +#endif 18 | } 19 | 20 | if (CDecl) { 21 | -------------------------------------------------------------------------------- /find.py: -------------------------------------------------------------------------------- 1 | import os 2 | libs_to_load = dict() 3 | for root, dirs, files in os.walk("/usr"): 4 | for name in files: 5 | if name.endswith(".so"): 6 | if name not in ["libhpx.so", "libhpxd.so"]: 7 | continue 8 | if "hpx" not in dirs: 9 | continue 10 | if "hpx-corot" in root: 11 | continue 12 | hpx_path = os.path.join(root, name) 13 | libs_to_load["hpx"] = hpx_path 14 | for name in files: 15 | if name.endswith(".so"): 16 | if name not in ["libboost_system.so", 17 | "libboost_filesystem.so", 18 | "libboost_program_options.so", 19 | "libboost_thread.so"]: 20 | continue 21 | libs_to_load[name] = os.path.join(root, name) 22 | for lib in libs_to_load.values(): 23 | print(lib) 24 | -------------------------------------------------------------------------------- /bot/teleplot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import json 3 | import numpy as np 4 | from random import randint 5 | 6 | randstr = '' 7 | for i in range(ord('a'),ord('z')+1): 8 | randstr += chr(i) 9 | for i in range(ord('A'),ord('Z')+1): 10 | randstr += chr(i) 11 | for i in range(ord('0'),ord('9')+1): 12 | randstr += chr(i) 13 | 14 | def randname(): 15 | s = '' 16 | for n in range(25): 17 | index = randint(0, len(randstr)-1) 18 | s += randstr[index] 19 | return s 20 | 21 | def plotjson(jtxt): 22 | outimg = 'image-'+randname()+'.png' 23 | jdata = json.loads(jtxt) 24 | plt.clf() 25 | for dataset in jdata["datasets"]: 26 | data = np.array(dataset["data"]) 27 | x, y = data[:,0], data[:,1] 28 | plt.plot(x, y, label=dataset["name"]) 29 | plt.legend() 30 | plt.savefig(outimg) 31 | return outimg 32 | 33 | if __name__ == "__main__": 34 | with open("test.json", "r") as fd: 35 | image = plotjson(fd.read()) 36 | print("image:",image) 37 | -------------------------------------------------------------------------------- /is_expr.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def is_expr(s): 4 | pat = r'''(?x) 5 | ( 6 | //.*| # one line comments 7 | /\*[\d\D]*?\*/| # long comments 8 | (\w+(?:::\w+)*(?:\.\w+(?:::\w+)*)*)| # identifier 9 | \s+| # spaces 10 | (<<|>>|[-+=*%/\[(]) # operator 11 | )''' 12 | res = [] 13 | while len(res) < 2: 14 | g = re.match(pat, s) 15 | if g: 16 | if g.group(2) is not None and g.group(2) not in ["is_same","decltype"]: 17 | res += ["S"] 18 | elif g.group(3) is not None: 19 | res += ["O"] 20 | s = s[g.end():] 21 | else: 22 | break 23 | if len(res) == 2 and res[0] == "S" and res[1] == "O": 24 | return True 25 | else: 26 | return False 27 | 28 | if __name__ == "__main__": 29 | for v in [("a++;",True), 30 | ("cout << \"Hello\" << endl;",True), 31 | ("struct foo {};",False), 32 | ("int fib(int n);",False), 33 | ("template fib(T t);",False), 34 | ("std::cout <<",True), 35 | ("hpx::cout <<",True), 36 | ("int a;",False), 37 | ("std::vector v;",False), 38 | ("v.clear();",True), 39 | ("cin >>",True), 40 | ("std::cin >>",True)]: 41 | print(v) 42 | s,r = v 43 | assert is_expr(s) == r 44 | -------------------------------------------------------------------------------- /docker-compose.server.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | volumes: 4 | # Provide persistent storage for users 5 | hpx_home: 6 | 7 | services: 8 | 9 | cxxex-server: 10 | # Download the full git repo and 11 | # uncomment the next lines if you want to build 12 | #build: 13 | # args: 14 | # BUILD_TYPE: Release 15 | # context: . 16 | # dockerfile: Dockerfile.ubuntu 17 | image: stevenrbrandt/cxxex-src 18 | container_name: cxxex-server 19 | user: root 20 | entrypoint: bash /root/startup.sh 21 | privileged: true 22 | #entrypoint: sleep infinity 23 | environment: 24 | # Code needed to create a login. Please edit before starting server. 25 | - "CODE=NippedTrains8" 26 | - "PORT=443" 27 | # Fill in the next lines appropriately for Github authentication. 28 | # - "OAUTH_CLIENT_ID=..." 29 | # - "OAUTH_CLIENT_SECRET=..." 30 | # - "OAUTH_CALLBACK_URL=https://hpx-tutorial.cct.lsu.edu/hub/oauth_callback" 31 | 32 | ports: 33 | # If you don't have a cert... 34 | #- "8088:80" 35 | # If you have a cert... 36 | - "443:443" 37 | volumes: 38 | # The expected cert name: /etc/pki/tls/certs/tutorial.cct.lsu.edu.cer 39 | # The expected key name: /etc/pki/tls/private/tutorial.cct.lsu.edu.key 40 | # Mount the directory with the cert if you are using a cert 41 | - /etc/pki:/etc/pki:Z 42 | - hpx_home:/home 43 | 44 | -------------------------------------------------------------------------------- /pipes3.py: -------------------------------------------------------------------------------- 1 | from subprocess import * 2 | import sys, os 3 | from pipes1 import delim, end, delimend 4 | 5 | 6 | def init_cling(): 7 | import pipes1 8 | return Popen([ 9 | "python3", 10 | pipes1.__file__ 11 | ], 12 | #bufsize=0, 13 | stdout=PIPE, 14 | stderr=PIPE, 15 | stdin=PIPE, 16 | universal_newlines=True) 17 | 18 | def readinp(inp): 19 | inbuf = '' 20 | while True: 21 | inbuf += inp.readline() 22 | if delim in inbuf: 23 | return inbuf 24 | 25 | def read_output(p,stream): 26 | outbuf = '' 27 | types = None 28 | while p.poll() is None: 29 | line = stream.readline() 30 | if line is None: 31 | break 32 | outbuf += line 33 | if delimend in outbuf: 34 | parts = outbuf.split(delim) 35 | assert parts[-1] == end+"\n" 36 | return parts[0:-1] 37 | os.set_blocking(stream.fileno(), False) 38 | outbuf += os.read(stream.fileno(),10000).decode() 39 | return [outbuf+"\nSegfault or Fatal error"] 40 | 41 | def run_cmd(p): 42 | cmd = readinp(sys.stdin) 43 | p.stdin.write(cmd) 44 | p.stdin.flush() 45 | result = read_output(p,p.stdout) 46 | print("result:",result) 47 | error = read_output(p,p.stderr) 48 | print("error:",error) 49 | 50 | #p = init_cling() 51 | #while p.poll() is None: 52 | # run_cmd(p) 53 | -------------------------------------------------------------------------------- /mkuser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from os import stat 4 | import os 5 | from subprocess import call 6 | import sys 7 | import pwd 8 | 9 | class UserExists(Exception): 10 | pass 11 | 12 | def mkuser(user): 13 | if not os.path.exists("/usr/enable_mkuser"): 14 | raise Exception("mkuser disabled") 15 | 16 | home = "/home/%s" % user 17 | cmd = ["useradd",user,"-s","/bin/bash"] 18 | if os.path.exists(home): 19 | uid = stat(home).st_uid 20 | try: 21 | return pwd.getpwuid(uid) 22 | # The user already exists, nothing to do 23 | raise UserExists("User exists: %s %d" % (user,uid)) 24 | except KeyError: 25 | pass 26 | cmd += ["-u",str(uid)] 27 | else: 28 | cmd += ["-m"] 29 | uids = set() 30 | for path in os.listdir("/home"): 31 | u = stat("/home/%s" % path).st_uid 32 | uids.add(u) 33 | for u in range(1000,100000): 34 | if u in uids: 35 | continue 36 | try: 37 | pwd.getpwuid(u) 38 | except KeyError: 39 | uid = u 40 | cmd += ["-u",str(uid)] 41 | break 42 | 43 | print(cmd) 44 | call(cmd) 45 | 46 | def getpwnam(user): 47 | try: 48 | return pwd.getpwnam(user) 49 | except: 50 | try: 51 | mkuser(user) 52 | except UserExists as ue: 53 | pass 54 | return pwd.getpwnam(user) 55 | 56 | if __name__ == "__main__": 57 | mkuser(sys.argv[1]) 58 | -------------------------------------------------------------------------------- /nb.py: -------------------------------------------------------------------------------- 1 | # This script is designed to test notebooks. 2 | # It is a work in progres... 3 | import os 4 | import json 5 | import sys 6 | import pipes3 7 | from termcolor import colored 8 | 9 | pinterp = None #pipes3.init_cling() 10 | print("Starting up...") 11 | 12 | def join(lines): 13 | if lines is None: 14 | return "" 15 | elif type(lines) == str: 16 | return lines 17 | else: 18 | return " ".join(lines) 19 | 20 | def process(jdata,key=None): 21 | if type(jdata) == list: 22 | for jd in jdata: 23 | process(jd) 24 | elif type(jdata) == dict and jdata.get("cell_type","") == "code": 25 | assert "source" in jdata 26 | assert type(jdata["source"]) == list 27 | src = "\n".join(jdata["source"]) 28 | pinterp.stdin.write(src+'$delim$\n') 29 | pinterp.stdin.flush() 30 | out = join(pipes3.read_output(pinterp, pinterp.stdout)) 31 | err = join(pipes3.read_output(pinterp, pinterp.stderr)) 32 | print("src:",colored(src,"cyan")) 33 | if "ASSERTION FAILURE" in err: 34 | print("out:",colored(out,"yellow")) 35 | print("err:",colored(err,"red")) 36 | print(colored("FAILED","red")) 37 | exit(1) 38 | else: 39 | print(colored("PASSED","green")) 40 | elif type(jdata) == dict: 41 | for k in jdata: 42 | jd = jdata[k] 43 | process(jd, key=k) 44 | elif type(jdata) in [str, int]: 45 | pass 46 | else: 47 | print("info:",type(jdata), jdata, key) 48 | raise Exception() 49 | 50 | for a in sys.argv[1:]: 51 | with open(a, "r") as fd: 52 | print(colored("Testing file:"+a,"magenta")) 53 | pinterp = pipes3.init_cling() 54 | jdata = json.loads(fd.read().strip()) 55 | process(jdata) 56 | print(colored("ALL TESTS PASSSED","green")) 57 | -------------------------------------------------------------------------------- /startup.sh: -------------------------------------------------------------------------------- 1 | cd /root 2 | 3 | # If oauth is to be used, 4 | # the following variables should be 5 | # set. 6 | # 7 | # export OAUTH_CLIENT_ID=... 8 | # export OAUTH_CLIENT_SECRET=... 9 | # export OAUTH_CALLBACK_URL=... 10 | 11 | # Load environment file if present 12 | if [ -d /env/env.sh ] 13 | then 14 | source /env/env.sh 15 | fi 16 | 17 | # Create the codefile needed to allow 18 | # user self-authorization. 19 | if [ "$CODE" != "" ] 20 | then 21 | echo $CODE > /usr/enable_mkuser 22 | fi 23 | 24 | if [ -r /home/passwd ] 25 | then 26 | cp /home/passwd /etc/passwd 27 | fi 28 | 29 | if [ -r /home/shadow ] 30 | then 31 | cp /home/shadow /etc/shadow 32 | fi 33 | 34 | # Re-create all existing users with the correct id 35 | # Needed if one mounts a persistent /home because 36 | # /etc/passwd cannot easily be mounted. So all user 37 | # data is normally lost on reboot. 38 | for h in /home/* 39 | do 40 | if [ -r $h/.bashrc ] 41 | then 42 | mkuser $(basename $h) 43 | fi 44 | done 45 | 46 | # If this JupyterHub is not setup for GitHubOAuth, then 47 | # it will instead use the Create Your Own Login Authenticator. 48 | if [ "$OAUTH_CLIENT_ID" = "" ] 49 | then 50 | echo Using invent your own password auth... 51 | cp /root/cyolauthenticator/docker/*.html /usr/local/share/jupyterhub/templates 52 | cp /root/login2.html /usr/local/share/jupyterhub/templates/login.html 53 | else 54 | if [ "$CODE" != "" ] 55 | then 56 | echo "Code is set." 57 | if [ "$BASE_URL" = "" ] 58 | then 59 | BASE_URL="/" 60 | fi 61 | perl -p -i -e "s{/BASE_URL/}{${BASE_URL}}g" /root/error.html 62 | cp /root/error.html /usr/local/share/jupyterhub/templates 63 | fi 64 | cp /root/login.html /usr/local/share/jupyterhub/templates 65 | echo Using GitHub OAuth... 66 | fi 67 | 68 | # Start the server. 69 | jupyterhub --ip 0.0.0.0 --port $PORT -f jup-config.py 70 | -------------------------------------------------------------------------------- /Pipe.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PIPE_HPP 2 | #define PIPE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | const char *RD_TMOUT = "/* Read Timeout */"; 15 | 16 | class Pipe { 17 | int pipe_fd[2]; 18 | public: 19 | Pipe() { 20 | pipe(pipe_fd); 21 | } 22 | ~Pipe() { 23 | close(pipe_fd[0]); 24 | close(pipe_fd[1]); 25 | } 26 | void writeInt(int n) { 27 | ::write(pipe_fd[1], &n, sizeof(n)); 28 | } 29 | void write(const char *s) { 30 | if(s == 0) 31 | s = ""; 32 | int n = strlen(s); 33 | writeInt(n); 34 | ::write(pipe_fd[1], s, n); 35 | } 36 | int readIntTmout(int tmout) { 37 | if(tmout > 0) { 38 | pollfd pd; 39 | pd.fd = pipe_fd[0]; 40 | pd.events = POLLIN;// 41 | pd.revents = 0; 42 | sigset_t sigmask; 43 | timespec tmo; 44 | tmo.tv_sec = tmout; 45 | tmo.tv_nsec = 0; 46 | int ready = ppoll(&pd, 1, &tmo, &sigmask); 47 | if(ready <= 0) { 48 | return -1; 49 | } 50 | } 51 | int n = readInt(); 52 | return n; 53 | } 54 | 55 | int readInt(const char *msg="") { 56 | int n = 0; 57 | ::read(pipe_fd[0], &n, sizeof(n)); 58 | return n; 59 | } 60 | char *read(const char *msg="") { 61 | int n = readInt(msg); 62 | if(n < 0) { 63 | n = strlen(RD_TMOUT); 64 | char *s = (char *)malloc(sizeof(char)*(n+1)); 65 | strcpy(s, RD_TMOUT); 66 | return s; 67 | } 68 | assert(n < 10000); 69 | char *s = (char *)malloc(sizeof(char)*(n+1)); 70 | ::read(pipe_fd[0], s, n); 71 | s[n] = 0; 72 | return s; 73 | } 74 | }; 75 | #endif 76 | -------------------------------------------------------------------------------- /teleplot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TELEPLOT_HPP 2 | #define TELEPLOT_HPP 3 | #include 4 | #include 5 | namespace teleplot { 6 | void plot(std::vector y) { 7 | std::cout << "{\"datasets\":[{\"name\":\"fig1\",\"data\":["; 8 | for(int i=0;i0) std::cout << ","; 10 |    std::cout << "[" << i << "," << y[i] << "]"; } 11 | std::cout << "]}]}" << std::endl; 12 | } 13 | void plotxy(std::vector x,std::vector y) { 14 | std::cout << "{\"datasets\":[{\"name\":\"fig1\",\"data\":["; 15 | for(int i=0;i0) std::cout << ","; 17 |    std::cout << "[" << x[i] << "," << y[i] << "]"; } 18 | std::cout << "]}]}" << std::endl; 19 | } 20 | void plot(std::vector y,std::vector y2) { 21 | std::cout << "{\"datasets\":["; 22 | std::cout << "{\"name\":\"fig1\",\"data\":["; 23 | for(int i=0;i0) std::cout << ","; 25 |    std::cout << "[" << i << "," << y[i] << "]"; } 26 | std::cout << "]},"; 27 | std::cout << "{\"name\":\"fig2\",\"data\":["; 28 | for(int i=0;i0) std::cout << ","; 30 |    std::cout << "[" << i << "," << y2[i] << "]"; } 31 | std::cout << "]}]}" << std::endl; 32 | } 33 | void plotxy(std::vector x,std::vector y,std::vector x2,std::vector y2) { 34 | std::cout << "{\"datasets\":[{\"name\":\"fig1\",\"data\":["; 35 | for(int i=0;i0) std::cout << ","; 37 |    std::cout << "[" << x[i] << "," << y[i] << "]"; } 38 | std::cout << "]},"; 39 | std::cout << "{\"name\":\"fig2\",\"data\":["; 40 | for(int i=0;i0) std::cout << ","; 42 |    std::cout << "[" << x2[i] << "," << y2[i] << "]"; } 43 | std::cout << "]}]}" << std::endl; 44 | } 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /notebooks/Lecture3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Numerical Limits" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "#include \n", 17 | "#include " 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "std::cout << \"type\\tmin()\\t\\tmax()\\n\";\n", 27 | "std::cout << \"int\\t\"\n", 28 | "<< std::numeric_limits::min() << '\\t'\n", 29 | "<< std::numeric_limits::max() << '\\n';\n", 30 | "std::cout << \"int\\t\"\n", 31 | "<< std::numeric_limits::min() << '\\t'\n", 32 | "<< std::numeric_limits::max() << '\\n';\n" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "## Floating point numbers" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | " std::cout << \"type\\tround()\\teps\\tmin()\\t\\tmax()\\n\";\n", 49 | " std::cout << \"double\\t\"\n", 50 | " << std::numeric_limits::round_error() <<'\\t'\n", 51 | " << std::numeric_limits::epsilon() <<'\\t'\n", 52 | " << std::numeric_limits::min() <<'\\t'\n", 53 | " << std::numeric_limits::max() <<'\\n';\n" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [] 62 | } 63 | ], 64 | "metadata": { 65 | "kernelspec": { 66 | "display_name": "C++17", 67 | "language": "C++", 68 | "name": "cling-cpp17" 69 | }, 70 | "language_info": { 71 | "codemirror_mode": "c++", 72 | "file_extension": ".c++", 73 | "mimetype": "text/x-c++src", 74 | "name": "c++" 75 | } 76 | }, 77 | "nbformat": 4, 78 | "nbformat_minor": 2 79 | } 80 | -------------------------------------------------------------------------------- /vector_pack_type.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Srinivas Yadav 2 | // Copyright (c) 2016-2017 Hartmut Kaiser 3 | // 4 | // SPDX-License-Identifier: BSL-1.0 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | #if defined(HPX_HAVE_DATAPAR_STD_EXPERIMENTAL_SIMD) 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | /////////////////////////////////////////////////////////////////////////////// 20 | namespace hpx { namespace parallel { namespace traits { 21 | /////////////////////////////////////////////////////////////////////////// 22 | namespace detail { 23 | template 24 | struct vector_pack_type 25 | { 26 | typedef std::experimental::fixed_size_simd type; 27 | }; 28 | 29 | template 30 | struct vector_pack_type 31 | { 32 | typedef typename std::conditional::value, 33 | std::experimental::simd_abi::native, Abi>::type abi_type; 34 | 35 | typedef std::experimental::simd type; 36 | }; 37 | 38 | template 39 | struct vector_pack_type 40 | { 41 | using type = T; 42 | }; 43 | } // namespace detail 44 | 45 | /////////////////////////////////////////////////////////////////////////// 46 | template 47 | struct vector_pack_type : detail::vector_pack_type 48 | { 49 | }; 50 | 51 | //////////////////////////////////////////////////////////////////// 52 | template 53 | struct vector_pack_mask_type>> 55 | { 56 | using type = typename T::mask_type; 57 | }; 58 | }}} // namespace hpx::parallel::traits 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /login.html: -------------------------------------------------------------------------------- 1 | {% extends "page.html" %} 2 | {% if announcement_login %} 3 | {% set announcement = announcement_login %} 4 | {% endif %} 5 | 6 | {% set announcement = '

Welcome to the HPX/C++ Server

' %} 7 | 8 | {% block login_widget %} 9 | {% endblock %} 10 | 11 | {% block main %} 12 | 13 | {% block login %} 14 |
15 | {% if custom_html %} 16 | {{ custom_html | safe }} 17 | {% elif login_service %} 18 | 23 | {% else %} 24 |
25 |
26 | Sign in 27 |
28 |
29 | 30 | 34 | 35 | {% if login_error %} 36 | 39 | {% endif %} 40 | 41 | 42 | 53 | 54 | 61 | 62 | 69 |
70 |
71 | {% endif %} 72 |
73 | {% endblock login %} 74 | 75 | {% endblock %} 76 | 77 | {% block script %} 78 | {{ super() }} 79 | 86 | 87 | {% endblock %} 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CxxExplorer 2 | This repo builds a JupyterHub/Jupyter notebook server which offers an interactive C++ experience. The primary interface for this is through cling notebooks (cling is the C++ interpreter). We extend the cling notebook with certain magics, (namely %%writefile and %%bash). However, additionally, we provide a %%cling magic cell for python notebooks, and a @py11 decorator--a way to create on-the-fly C++ functions using Pybind11. 3 | 4 | To build, just uncomment the build lines in the clinet docker file below and run "docker-compose build". 5 | 6 | You can run the CxxExplorer as a notebook using this docker-compose.yml file: 7 | ``` 8 | version: '2' 9 | 10 | volumes: 11 | cxxex_home: 12 | 13 | services: 14 | 15 | cxxex-workspace: 16 | # Uncomment the next lines if you want to build. 17 | # You probably want to have a pretty powerful 18 | # machine if you want to do this. 19 | # build: 20 | # args: 21 | # CPUS: 12 22 | # BUILD_TYPE: Release 23 | # context: . 24 | # dockerfile: Dockerfile 25 | image: stevenrbrandt/cxxex-src 26 | container_name: cxxex 27 | user: jovyan 28 | environment: 29 | - "PORT=80" 30 | # Please edit this line 31 | - "SECRET_TOKEN=love" 32 | ports: 33 | - "8004:80" 34 | volumes: 35 | - cxxex_home:/home 36 | ``` 37 | Or you can run it as a server 38 | ``` 39 | version: '2' 40 | 41 | volumes: 42 | cxxex_home: 43 | 44 | services: 45 | 46 | cxxex-workspace: 47 | image: stevenrbrandt/cxxex-src 48 | container_name: cxxex 49 | user: root 50 | entrypoint: bash /root/startup.sh 51 | environment: 52 | - "PORT=443" 53 | 54 | # Option 1: Use GitHubOAuth. To run the 55 | # server this way, fill in these variables 56 | # - "OAUTH_CLIENT_ID=..." 57 | # - "OAUTH_CLIENT_SECRET=..." 58 | # - "OAUTH_CALLBACK_URL=..." 59 | 60 | # Option 2: Use the Create Your Own Login (CYOL) 61 | # Authenticator. This will happen if the above 62 | # variables are not set. 63 | 64 | # With Ooption 1, only github users whose names 65 | # appear in /home/allowed_users.txt are 66 | # permitted to login. 67 | # If you set a CODE, then any user with 68 | # that code can add themselves to the allowed 69 | # users list. 70 | 71 | # With Option 2:, the CODE enables users to 72 | # select and create their own login name and 73 | # password. 74 | - "CODE=frog" 75 | 76 | ports: 77 | - "8004:443" 78 | volumes: 79 | - cxxex_home:/home 80 | # expecting these if the port is 443 81 | # - cert_file:/etc/pki/tls/certs/tutorial.cct.lsu.edu.cer 82 | # - key_file:/etc/pki/tls/private/tutorial.cct.lsu.edu.key 83 | ``` 84 | 85 | ## References 86 | 87 | * P. Diehl and S. R. Brandt, Interactive C++ code development using C++Explorer and GitHub Classroom for educational purposes, In Proceedings of Gateways 2020, Science Gateways Community Institute (SGCI), [Link](https://osf.io/qbtj3/) 88 | -------------------------------------------------------------------------------- /jup-config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from tornado import web 3 | from time import sleep 4 | 5 | if "OAUTH_CLIENT_ID" in os.environ: 6 | from oauthenticator.github import GitHubOAuthenticator 7 | 8 | class MyGitHubOAuthenticator(GitHubOAuthenticator): 9 | async def authenticate(self, handler, data=None): 10 | if data is None: 11 | userdict = await super().authenticate(handler, data) 12 | data = {} 13 | with open("/tmp/log.txt", "a") as fd: 14 | print("git:",userdict, file=fd) 15 | else: 16 | userdict = { "name":data["username"] } 17 | with open("/tmp/log.txt", "a") as fd: 18 | print("nogit:",data, file=fd) 19 | allowed_users = "/home/allowed_users.txt" 20 | users = set() 21 | if os.path.exists(allowed_users): 22 | with open(allowed_users, "r") as fd: 23 | for user in fd.readlines(): 24 | users.add(user.strip()) 25 | enable_mkuser = os.path.exists("/usr/enable_mkuser") 26 | if "code" in data and userdict["name"] not in users and enable_mkuser: 27 | with open("/usr/enable_mkuser", "r") as fd: 28 | code = fd.read().strip() 29 | if data["code"] == code: 30 | with open(allowed_users, "a") as fd: 31 | print(userdict["name"], file=fd) 32 | users.add(userdict["name"]) 33 | else: 34 | sleep(10) 35 | if userdict["name"] in users: 36 | return userdict 37 | elif enable_mkuser: 38 | e = web.HTTPError(403, "User '%s' does not have access. Please request with a code below." % userdict['name']) 39 | e.my_message = 'Login' 40 | e.user = userdict["name"] 41 | raise e 42 | else: 43 | raise web.HTTPError(403, "User '%s' has not been given access. Please request it from your instructor." % userdict['name']) 44 | 45 | c.JupyterHub.authenticator_class = MyGitHubOAuthenticator 46 | else: 47 | c.JupyterHub.authenticator_class = 'cyolauthenticator.CYOLAuthenticator' 48 | c.JupyterHub.log_level = 'DEBUG' 49 | c.Spawner.debug = True 50 | c.LocalProcessSpawner.debug = True 51 | 52 | # If the port is set to 443, a key & cert should be mounted in the container. 53 | if os.environ["PORT"] == "443": 54 | c.JupyterHub.ssl_cert = '/etc/pki/tls/certs/tutorial.cct.lsu.edu.cer' 55 | c.JupyterHub.ssl_key = '/etc/pki/tls/private/tutorial.cct.lsu.edu.key' 56 | 57 | if 'BASE_URL' in os.environ: 58 | c.JupyterHub.base_url = os.environ['BASE_URL'] #'/hpx/' 59 | 60 | c.NotebookApp.terminado_settings = { 'shell_command': 'bash' } 61 | 62 | def pre_spawn_hook(spawner): 63 | import mkuser 64 | print("Running pre-spawn hook") 65 | print("User:",spawner.user.name) 66 | mkuser.mkuser(spawner.user.name) 67 | 68 | # Configure to use Github Auth 69 | if "OAUTH_CLIENT_ID" in os.environ: 70 | c.Spawner.pre_spawn_hook = pre_spawn_hook 71 | -------------------------------------------------------------------------------- /pipes1.py: -------------------------------------------------------------------------------- 1 | import ctypes, os, sys, re 2 | from signal import * 3 | 4 | delim = '$delim$' 5 | end = '$end$' 6 | delimend = delim+end 7 | 8 | class my_void_p(ctypes.c_void_p): 9 | pass 10 | 11 | def clearout(sig,frame): 12 | sys.stdout.write(delimend) 13 | sys.stdout.flush() 14 | sys.stderr.write(delimend) 15 | sys.stderr.flush() 16 | exit(2) 17 | 18 | #signal(SIGABRT.value, clearout) 19 | 20 | class cling: 21 | def __init__(self): 22 | hpx_debug = False 23 | with open("/usr/hpx-libs.txt", "r") as fd: 24 | for line in fd.readlines(): 25 | if "libhpxd.so" in line: 26 | hpx_debug = True 27 | ctypes.CDLL(line.strip(),ctypes.RTLD_GLOBAL) 28 | if hpx_debug: 29 | flags = [b"-DHPX_DEBUG", b"-lhpxd"] 30 | else: 31 | flags = [b"-lhpx"] 32 | self.clingJupyter = ctypes.CDLL("/usr/lib/libclingJupyter.so", mode = ctypes.RTLD_GLOBAL) 33 | clingInstDir=b"/usr/lib/clang/5.0.0" 34 | stdopt=b"-std=c++17" 35 | argv = [ 36 | b"cling", 37 | b"-I" + clingInstDir + b"/include/", 38 | b"-std=c++17", 39 | b"-I.", 40 | b"-L/usr/local/lib64", 41 | #b"-lboost_filesystem", 42 | #b"-lboost_program_options", 43 | #b"-lboost_system" 44 | #b"-I/usr/local/include", 45 | #b"-I/usr/include" 46 | ] + flags 47 | argc = len(argv) 48 | CharPtrArrayType = ctypes.c_char_p * argc 49 | llvmResourceDirCP = ctypes.c_char_p("/usr".encode('utf8')) 50 | sideband_pipe, pipe_in = os.pipe() 51 | self.clingJupyter.cling_create.restype = my_void_p 52 | self.clingJupyter.cling_eval.restype = my_void_p 53 | self.interp = self.clingJupyter.cling_create( 54 | ctypes.c_int(argc), CharPtrArrayType(*argv), llvmResourceDirCP, pipe_in) 55 | 56 | def run_cmd(self,code): 57 | stringResult = self.clingJupyter.cling_eval(self.interp, ctypes.c_char_p(code.encode('utf8'))) 58 | if stringResult: 59 | s = ctypes.cast(stringResult, ctypes.c_char_p).value.decode('utf8', 'replace').strip() 60 | if s != '': 61 | print(delim) 62 | print(s) 63 | print(delimend) 64 | sys.stdout.flush() 65 | sys.stderr.flush() 66 | print(delimend,file=sys.stderr) 67 | sys.stderr.flush() 68 | 69 | cl = cling() 70 | 71 | root_pid = os.getpid() 72 | 73 | def readinp(inp): 74 | inbuf = '' 75 | while True: 76 | inbuf += inp.readline() 77 | if delim in inbuf: 78 | parts = inbuf.split(delim) 79 | inbuf = parts[0].strip()+'\n' 80 | return inbuf 81 | 82 | if __name__ == "__main__": 83 | if len(sys.argv) > 2: 84 | cl.run_cmd("#include ") 85 | #cl.run_cmd(".L x.cpp") 86 | #cl.run_cmd("a") 87 | #cl.run_cmd("int fut = run_hpx([]()->int{ return 4; });") 88 | cl.run_cmd('auto b = fun([](){ return 42; });') 89 | else: 90 | while True: 91 | inbuf = readinp(sys.stdin) 92 | cl.run_cmd(inbuf) 93 | -------------------------------------------------------------------------------- /bot/telecling.py: -------------------------------------------------------------------------------- 1 | import pipes3 2 | from is_expr import is_expr 3 | 4 | from traceback import print_exc 5 | from IPython.core.magic import register_cell_magic 6 | from IPython.display import display, HTML 7 | import html 8 | import inspect 9 | import re 10 | 11 | def color_text(color, text): 12 | if text != "": 13 | display(HTML(("
" % color)+html.escape(text)+'
')) 14 | 15 | def replvar(var,globs): 16 | newvar = '' 17 | last = 0 18 | for g in re.finditer(r'{(\w+)}',var): 19 | if g.group(1) in globs: 20 | newvar += var[last:g.span(0)[0]] 21 | newvar += str(globs[g.group(1)]) 22 | last = g.span(0)[1] 23 | newvar += var[last:] 24 | return newvar 25 | 26 | pinterp = None 27 | prev_history = [] 28 | history = [] 29 | 30 | def replay(n=-1): 31 | global prev_history, history, pinterp 32 | for cmd in prev_history[0:n]: 33 | history += [cmd] 34 | color_text("#eeeeee","replaying: "+cmd) 35 | pinterp.stdin.write(cmd+'$delim$\n') 36 | pinterp.stdin.flush() 37 | out = pipes3.read_output(pinterp, pinterp.stdout) 38 | err = pipes3.read_output(pinterp, pinterp.stderr) 39 | color_text("#f8f8ff",out[0]) 40 | color_text("#ffcccc",err[0]) 41 | if "Segfault or Fatal error" in out[0]: 42 | pinterp.wait() 43 | pinterp = pipes3.init_cling() 44 | 45 | class ClingServer: 46 | def __init__(self): 47 | self.pinterp = None 48 | self.history = None 49 | self.prev_history = None 50 | self.count = 0 51 | def exec_code(self, code): 52 | try: 53 | if code.strip() == ".restart": 54 | self.count = 0 55 | self.pinterp = pipes3.init_cling() 56 | code = ""; 57 | self.count += 1 58 | code = re.sub(r'«','<<',code) 59 | if self.pinterp is None: 60 | self.pinterp = pipes3.init_cling() 61 | pinterp = self.pinterp 62 | caller = inspect.stack()[-1][0].f_globals 63 | code = replvar(code, caller) 64 | if is_expr(code): 65 | code = ".expr "+code 66 | #history += [code] 67 | pinterp.stdin.write(code+"$delim$\n") 68 | pinterp.stdin.flush() 69 | out = pipes3.read_output(pinterp, pinterp.stdout) 70 | err = pipes3.read_output(pinterp, pinterp.stderr) 71 | if "Segfault or Fatal error" in out[0]: 72 | pinterp.wait() 73 | self.pinterp = pipes3.init_cling() 74 | self.count = 1 75 | pinter = self.pinterp 76 | out += ["Server Restart"] 77 | #prev_history = history 78 | #history = [] 79 | res = out + err 80 | #res = {"out":out[0], "err":err[0], "type":None} 81 | #color_text("#f8f8ff",out[0]) 82 | #if len(out) > 1: 83 | # color_text("#eeffee",out[1]) 84 | # res["type"] = out[1] 85 | except Exception as e: 86 | print_exc() 87 | res = [str(e)] 88 | #color_text("#ffcccc",err[0]) 89 | #if line2 is not None: 90 | # caller[line2.strip()] = res 91 | return res 92 | -------------------------------------------------------------------------------- /login2.html: -------------------------------------------------------------------------------- 1 | {% extends "page.html" %} 2 | {% if announcement_login %} 3 | {% set announcement = announcement_login %} 4 | {% endif %} 5 | 6 | {% set announcement = '

Welcome to the Tutorial Server

' %} 7 | 8 | {% block login_widget %} 9 | {% endblock %} 10 | 11 | {% block main %} 12 | 13 | {% block login %} 14 |
15 | {% if custom_html %} 16 | {{ custom_html | safe }} 17 | {% elif login_service %} 18 | 23 | {% else %} 24 |
25 |
26 | Sign in 27 |
28 |
29 | 30 |

To create a new user, use the 31 | same password and password2, fill in the value for 32 | 'code' supplied by the tutorial presenter, and click the create button. 33 | If it is available, your username 34 | will be created.

35 | 36 |

For subsequent logins, it is not necessary to 37 | fill in the password2 field.

38 | 39 | {% if login_error %} 40 | 43 | {% endif %} 44 | 45 | 46 | 57 | 58 | 65 | 66 | 73 |
74 | 75 | 82 | 83 | 90 | 91 | 98 |
99 |
100 | {% endif %} 101 |
102 | {% endblock login %} 103 | 104 | {% endblock %} 105 | 106 | {% block script %} 107 | {{ super() }} 108 | 115 | 116 | {% endblock %} 117 | -------------------------------------------------------------------------------- /error.html: -------------------------------------------------------------------------------- 1 | {% extends "page.html" %} 2 | 3 | {% block login_widget %} 4 | {% endblock %} 5 | 6 | {% block main %} 7 | 8 |
9 | {% block h1_error %} 10 |

11 | {{status_code}} : {{status_message}} 12 |

13 | {% if exception and exception.my_message %} 14 |

{{ exception.my_message }}

15 | {% endif %} 16 | {% endblock h1_error %} 17 | {% block error_detail %} 18 | {% if message %} 19 |

20 | {{message}} 21 |

22 | {% endif %} 23 | {% if message_html %} 24 |

25 | {{message_html | safe}} 26 |

27 | {% endif %} 28 | {% if extra_error_html %} 29 |

30 | {{extra_error_html | safe}} 31 |

32 | {% endif %} 33 | {% endblock error_detail %} 34 | 35 | {% if exception.my_message == 'Login' %} 36 |

If you enter the correct code in the form below, your 37 | github username will be added to the list of allowed users. 38 | If you enter the incorrect code, this page will reload. 39 |

40 |
41 |
42 |
43 | Sign in 44 |
45 |
46 | 47 | 51 | 52 | {% if login_error %} 53 | 56 | {% endif %} 57 | 58 | {{exception.user}}
70 | 71 | 78 | 79 | 86 |
87 |
88 |
89 | {% endif %} 90 | 91 |
92 | 93 | {% endblock %} 94 | 95 | {% block script %} 96 | {{super()}} 97 | 98 | 124 | {% endblock %} 125 | -------------------------------------------------------------------------------- /Augment_Kernel.hpp: -------------------------------------------------------------------------------- 1 | ///----------------------------------- 2 | /// Inserted code 3 | int parent = getpid(); 4 | int child = -1; 5 | int child2 = -1; 6 | 7 | const char *FAIL="~**FAIL**~"; 8 | 9 | const int trapio_buf_siz = 10000; 10 | 11 | std::string fname(int fd,int pid) { 12 | std::ostringstream fname; 13 | fname << "out-" << fd << "-" << pid; 14 | return fname.str(); 15 | } 16 | 17 | std::string fnread(std::string fn) { 18 | int fd = open(fn.c_str(), O_RDONLY); 19 | char buf[trapio_buf_siz+1]; 20 | int n = read(fd, buf, trapio_buf_siz); 21 | return std::string(buf, n); 22 | } 23 | 24 | struct TrapIO { 25 | int dupfd, fd, rd; 26 | char buf[trapio_buf_siz+1]; 27 | std::string fstr; 28 | TrapIO(int fd_) : fd(fd_) { 29 | dupfd = dup(fd); 30 | fstr = fname(fd, getpid()); 31 | int fdalt = open(fstr.c_str(), O_WRONLY|O_TRUNC|O_CREAT, 0600); 32 | if(fdalt >= 0) { 33 | close(fd); 34 | dup(fdalt); 35 | close(fdalt); 36 | } 37 | rd = open(fstr.c_str(), O_RDONLY); 38 | //::unlink(fstr.c_str()); 39 | } 40 | char *get() { 41 | int nbytes = read(rd, buf, trapio_buf_siz); 42 | buf[nbytes] = 0; 43 | return buf; 44 | } 45 | void cleanup() { 46 | close(fd); 47 | dup(dupfd); 48 | close(dupfd); 49 | unlink(fstr.c_str()); 50 | } 51 | }; 52 | 53 | Pipe chan; 54 | Pipe code_chan; 55 | 56 | void 57 | sig_exit(int sig_num) 58 | { 59 | std::cerr << "Died from signal " << sig_num << std::endl; 60 | exit(0); 61 | } 62 | 63 | char* cling_eval(TheMetaProcessor *metaProc, const char *code) { 64 | bool good = false; 65 | char *result = 0; 66 | if(child < 0) { 67 | child = fork(); 68 | } 69 | if(child == 0) { 70 | signal(SIGINT , sig_exit); 71 | signal(SIGABRT , sig_exit); 72 | signal(SIGILL , sig_exit); 73 | signal(SIGFPE , sig_exit); 74 | signal(SIGSEGV, sig_exit); 75 | signal(SIGTERM , sig_exit); 76 | while(true) { 77 | Pipe chan2; 78 | char *code_c = code_chan.read("code"); 79 | child2 = fork(); 80 | if(child2 == 0) { 81 | TrapIO fd1(1), fd2(2); 82 | char *result = cling_eval_inner(metaProc, code_c, good); 83 | 84 | // Ensure all IO is flushed 85 | std::cout << std::flush; 86 | std::cerr << std::flush; 87 | fflush(stdout); 88 | fflush(stderr); 89 | 90 | fd1.cleanup(); 91 | fd2.cleanup(); 92 | 93 | chan2.writeInt(good); 94 | if(good) 95 | chan.writeInt(getpid()); 96 | else 97 | chan.writeInt(0); 98 | chan.write(fd1.get()); 99 | chan.write(fd2.get()); 100 | chan.write(result); 101 | if(!good) 102 | exit(1); 103 | } else { 104 | int good = chan2.readIntTmout(1); 105 | for(int t=0;t<50;t++) { 106 | if(good >= 0) { 107 | // child responded 108 | break; 109 | } 110 | int wstatus; 111 | if(waitpid(child2, &wstatus, WNOHANG) > 0) { 112 | // child has exited 113 | break; 114 | } 115 | // try again 116 | good = chan2.readIntTmout(5); 117 | } 118 | if(good > 0) { 119 | exit(0); 120 | } else if(good < 0) { 121 | chan.writeInt(0); 122 | std::string fout = fname(1, child2); 123 | std::string ferr = fname(2, child2); 124 | std::string bout = fnread(fout); 125 | std::string berr = fnread(ferr); 126 | chan.write(bout.c_str()); 127 | chan.write(berr.c_str()); 128 | chan.write("Unknown failure"); 129 | ::unlink(fout.c_str()); 130 | ::unlink(ferr.c_str()); 131 | } else { 132 | int status; 133 | wait(&status); 134 | } 135 | } 136 | } 137 | } else { 138 | code_chan.write(code); 139 | int pid = chan.readInt(); 140 | 141 | result = chan.read("stdout"); 142 | std::cout << result << std::flush; 143 | 144 | result = chan.read("stderr"); 145 | std::cerr << result << std::flush; 146 | 147 | result = chan.read("result"); 148 | 149 | if(pid == child || pid == 0) { 150 | ; 151 | } else { 152 | int status; 153 | wait(&status); 154 | child = pid; 155 | } 156 | } 157 | return result; 158 | } 159 | ///----------------------------------- 160 | -------------------------------------------------------------------------------- /cling.py: -------------------------------------------------------------------------------- 1 | import pipes3 2 | 3 | from traceback import print_exc 4 | from IPython.core.magic import register_cell_magic 5 | from IPython.display import display, HTML, Image 6 | import html 7 | import inspect 8 | import re 9 | from pipes1 import delim 10 | #from is_expr import is_expr 11 | from cin import hpxify 12 | import os 13 | from subprocess import Popen, PIPE 14 | 15 | def show_images(): 16 | for fn in os.listdir("."): 17 | if fn.endswith(".pbm"): 18 | img = fn[:-4]+".png" 19 | if (not os.path.exists(img)) or os.stat(fn).st_mtime > os.stat(img).st_mtime: 20 | p = Popen(["convert", fn, img], stdout=PIPE, stderr=PIPE, universal_newlines=True) 21 | o, e = p.communicate() 22 | if os.path.exists(img): 23 | display(HTML("

Image file generated: "+img+"

")) 24 | display(Image(img)) 25 | 26 | 27 | @register_cell_magic 28 | def bash(line, cell): 29 | get_ipython().system(cell) 30 | show_images() 31 | 32 | results = {} 33 | 34 | def color_text(color, text): 35 | if text != "": 36 | display(HTML(("
" % color)+html.escape(text)+'
')) 37 | 38 | def replvar(var,globs): 39 | newvar = '' 40 | last = 0 41 | for g in re.finditer(r'{(\w+)}',var): 42 | if g.group(1) in globs: 43 | newvar += var[last:g.span(0)[0]] 44 | newvar += str(globs[g.group(1)]) 45 | last = g.span(0)[1] 46 | newvar += var[last:] 47 | return newvar 48 | 49 | pinterp = None 50 | prev_history = [] 51 | history = [] 52 | 53 | def replay(n=-1): 54 | global prev_history, history, pinterp 55 | pinterp.kill() 56 | pinterp.wait() 57 | pinterp = pipes3.init_cling() 58 | for cmd in history[0:n]: 59 | history += [cmd] 60 | color_text("#eeeeee","replaying: "+cmd) 61 | pinterp.stdin.write(cmd+delim+'\n') 62 | pinterp.stdin.flush() 63 | out = pipes3.read_output(pinterp, pinterp.stdout) 64 | err = pipes3.read_output(pinterp, pinterp.stderr) 65 | color_text("#f8f8ff",out[0]) 66 | color_text("#ffcccc",err[0]) 67 | if "Segfault or Fatal error" in out[0]: 68 | pinterp.wait() 69 | pinterp = pipes3.init_cling() 70 | 71 | @register_cell_magic 72 | def cling(line, code): 73 | global pinterp, history, prev_history, results 74 | if line is None: 75 | line2 = None 76 | else: 77 | line2 = re.sub(r'--init\b','',line) 78 | if pinterp is None: 79 | pinterp = pipes3.init_cling() 80 | elif line != line2: 81 | pinterp = pipes3.init_cling() 82 | try: 83 | istack = inspect.stack() 84 | # Figure out where in the stack the symbol is supposed to go 85 | #for i in range(len(istack)): 86 | # print("stack:",i,istack[i][0].f_globals.get("foo","UNDEF")) 87 | if len(istack) > 2: 88 | caller = istack[2][0].f_globals 89 | else: 90 | caller = {} 91 | #code = replvar(code, results) 92 | code = replvar(code, caller) 93 | if code.startswith(".expr "): 94 | pass 95 | #elif is_expr(code): 96 | # code = ".expr "+code 97 | code, use_hpx, has_main, msg = hpxify(code) 98 | if "$debug=true" in code: 99 | print("HPXIFY:",code) 100 | print("USE HPX:",use_hpx) 101 | print("MSG:",msg) 102 | history += [code] 103 | pinterp.stdin.write(code+delim+"\n") 104 | pinterp.stdin.flush() 105 | out = pipes3.read_output(pinterp, pinterp.stdout) 106 | err = pipes3.read_output(pinterp, pinterp.stderr) 107 | #if "Segfault or Fatal error" in out[0] or "signal 11" in err[0]: 108 | # pinterp.kill() 109 | # pinterp.wait() 110 | # pinterp = pipes3.init_cling() 111 | # prev_history = history 112 | # history = [] 113 | res = {"out":out[0], "err":err[0], "type":None} 114 | color_text("#f8f8ff",out[0]) 115 | if len(out) > 1: 116 | color_text("#eeffee",out[1]) 117 | res["type"] = out[1] 118 | color_text("#ffcccc",err[0]) 119 | if line2 is not None: 120 | results[line2.strip()] = res 121 | except Exception as e: 122 | print_exc() 123 | finally: 124 | show_images() 125 | 126 | if __name__ == "__main__": 127 | cling("",""" 128 | 129 | #include 130 | #include 131 | 132 | // The Fibonacci function written using hpx async 133 | int fib(int n) { 134 | if(n < 2) return n; 135 | 136 | // launch a thread 137 | hpx::future f1 = hpx::async(hpx::launch::async, fib,n-1); 138 | 139 | // do work while the thread is running 140 | int f2 = fib(n-2); 141 | 142 | // wait for the thread to complete 143 | return f1.get() + f2; 144 | }""") 145 | cling("",""" 146 | { 147 | int n=10; 148 | std::cout << "fib(" << n << ")=" << fib(n) << "x" << std::endl; 149 | } 150 | """) 151 | -------------------------------------------------------------------------------- /hpxcxx: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3.10 2 | # 3 | # Copyright (c) 2014 Steven R. Brandt 4 | # 5 | # SPDX-License-Identifier: BSL-1.0 6 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 7 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 | 9 | import sys 10 | import os 11 | import re 12 | import subprocess 13 | 14 | app = None 15 | app_name = None 16 | application = False 17 | component = False 18 | minusc = False 19 | output = None 20 | args = ["/usr/bin/c++"] 21 | libs = [] 22 | 23 | def remove_suffix(nm): 24 | if nm.startswith("lib"): 25 | nm = nm[3:-1] 26 | n = nm.rfind('.') 27 | if n > 0: 28 | return nm[0:n] 29 | else: 30 | return nm 31 | 32 | # Deduce the path to HPX's pkgconfig. 33 | pkgconfpath = [] 34 | if "HPX_LOCATION" in os.environ: 35 | pkgconfpath += [ 36 | os.path.join(os.environ["HPX_LOCATION"],"lib","pkgconfig")] 37 | pkgconfpath += [ 38 | os.path.join("/usr/local/hpx-corot","lib","pkgconfig"), # install directory 39 | os.path.join("/usr/local/hpx-corot","lib64","pkgconfig"), # install directory 40 | os.path.join(os.path.dirname(sys.argv[0]),"..","lib","pkgconfig"), 41 | os.path.join("opt","hpx","lib","pkgconfig"), 42 | os.path.join("/usr","bin","hpx","lib","pkgconfig"), 43 | os.path.join("/usr","local","corot","bin","hpx","lib","pkgconfig"), 44 | os.path.join(os.environ["HOME"],"install","hpx","lib","pkgconfig"), 45 | os.path.join(os.environ["HOME"],"hpx","lib","pkgconfig") 46 | ] 47 | 48 | def usage(): 49 | sys.stderr.write(""" 50 | Usage: hpxcxx --comp=ComponentName flags files 51 | Usage: hpxcxx --exe=ApplicationName flags files 52 | Usage: hpxcxx -c flags files 53 | 54 | The hpxcxx command requires that you build either 55 | a component, an application, or that you specify 56 | the -c flag. If you are building against a debug 57 | build, you need to specify --db. 58 | If release-with-debug-info, specify --rd 59 | If minsize-release specify --mr. All other flags 60 | are passed through to the underlying C++ compiler. 61 | """) 62 | sys.exit(2) 63 | 64 | pkgconf_suffix = '_release' 65 | i = 1 66 | while i < len(sys.argv): 67 | 68 | # Need to parse libraries to go after the 69 | # pkg-config argument 70 | if sys.argv[i] == '-l': 71 | libs += [sys.argv[i],sys.argv[i+1]] 72 | i += 1 73 | elif sys.argv[i].startswith('-l'): 74 | libs += [sys.argv[i]] 75 | 76 | elif sys.argv[i].startswith('--exe='): 77 | output=sys.argv[i][6:] 78 | app = output 79 | #args += ['-o',app+'.exe'] 80 | application = True 81 | elif sys.argv[i].startswith('--comp='): 82 | app_name = sys.argv[i][7:] 83 | output='lib'+app_name+'.so' 84 | app = output 85 | component = True 86 | 87 | # Need to determine if this is an application, 88 | # and if so what it's name is 89 | elif sys.argv[i] == '-o': 90 | i += 1 91 | output = sys.argv[i] 92 | elif sys.argv[i].startswith('-o'): 93 | output = sys.argv[i][2:] 94 | elif sys.argv[i] == '-c': 95 | minusc = True 96 | pass 97 | elif sys.argv[i].startswith('-db'): 98 | pkgconf_suffix = '_debug' 99 | elif sys.argv[i].startswith('--rd'): 100 | pkgconf_suffix = '_relwithdebuginfo' 101 | elif sys.argv[i].startswith('--mr'): 102 | pkgconf_suffix = '_minsizerel' 103 | else: 104 | args += [sys.argv[i]] 105 | 106 | i += 1 107 | 108 | pkgconf = None 109 | for path in pkgconfpath: 110 | found = False 111 | for suffix in [pkgconf_suffix, "_release", "_relwithdebuginfo","_debug"]: 112 | hpath = os.path.join(path,"hpx_application")+suffix+".pc" 113 | if os.path.exists(hpath): 114 | pkgconf = path 115 | pkgconf_suffix = suffix 116 | found = True 117 | break 118 | if found: 119 | break 120 | 121 | if pkgconf == None: 122 | sys.stderr.write('Cannot locate HPX\n') 123 | usage() 124 | 125 | pkg = 'PKG_CONFIG_PATH' 126 | if pkg in os.environ: 127 | os.environ[pkg] += ":" + pkgconf 128 | else: 129 | os.environ[pkg] = pkgconf 130 | 131 | if application: 132 | args += ["`pkg-config --cflags --libs hpx_application" + pkgconf_suffix + "`"] 133 | elif component: 134 | args += ["`pkg-config --cflags --libs hpx_component" + pkgconf_suffix + "`"] 135 | else: 136 | args += ["`pkg-config --cflags hpx_application" + pkgconf_suffix + "`"] 137 | 138 | if not component and not application and not minusc: 139 | usage() 140 | 141 | if output != None: 142 | args = args[0:1]+['-o',output]+args[1:] 143 | 144 | args += libs 145 | 146 | if application: 147 | if app != None: 148 | args += ['-DHPX_APPLICATION_NAME='+app] 149 | else: 150 | args += ['-DHPX_APPLICATION_NAME=hpx_aout'] 151 | elif component: 152 | args += ['-DHPX_COMPONENT_NAME='+app_name] 153 | else: 154 | args += ['-c'] 155 | 156 | cmd = ' '.join(args) 157 | sys.stdout.write(pkg+'='+pkgconf+'\n') 158 | sys.stdout.write(cmd+'\n') 159 | sys.stdout.flush() 160 | 161 | p = subprocess.Popen(cmd, shell=True) 162 | p.communicate() 163 | sys.exit(p.returncode) 164 | 165 | -------------------------------------------------------------------------------- /notebooks/Lecture1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "

Notebook for Lecture 1

" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "#include " 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "

Structure of a C++ Program

" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "std::cout << \"Hello\" << std::endl;" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "

Using loops and counting

" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "size_t result = 0;" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | ".expr\n", 58 | "for( size_t i = 1; i != 5; i++){\n", 59 | " result = result + i;\n", 60 | "}\n", 61 | "std::cout << \"result=\" << result << std::endl;" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "

The while statement

" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | ".expr\n", 78 | "result = 0;\n", 79 | "{\n", 80 | " size_t i = 1;\n", 81 | " while (i != 5 ) {\n", 82 | " result += i;\n", 83 | " i++;\n", 84 | " }\n", 85 | " std::cout << \"result=\" << result << std::endl;\n", 86 | "}" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "

Conditionals

" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | ".expr\n", 103 | "result = 0;\n", 104 | "for( size_t i = 1; i != 5; i++){\n", 105 | " if(i % 1 == 0)\n", 106 | " result = result + i;\n", 107 | " else\n", 108 | " result = result + i * i;\n", 109 | "}\n", 110 | "std::cout << \"result=\" << result << std::endl;" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "

Creating a file with a notebook

" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "%%writefile name.txt\n", 127 | "Gertrude" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "

Reading strings

" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "#include \n", 144 | "#include " 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "std::string name;" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | ".expr\n", 163 | "std::ifstream inf(\"name.txt\");\n", 164 | "// Read the name\n", 165 | "inf >> name;\n", 166 | "// Writing the name\n", 167 | "std::cout << \"Hi, \" << name << \"!\" << std::endl;" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "

More functionality of strings

" 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "const std :: string greetings = \"Hi, \" + name + \"!\";" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "std::cout << greetings << std::endl;" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [ 201 | "const size_t length = greetings.size();" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": null, 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "std::cout << \"length=\" << length << std::endl;" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "metadata": {}, 217 | "outputs": [], 218 | "source": [] 219 | } 220 | ], 221 | "metadata": { 222 | "kernelspec": { 223 | "display_name": "C++17", 224 | "language": "C++", 225 | "name": "cling-cpp17" 226 | }, 227 | "language_info": { 228 | "codemirror_mode": "c++", 229 | "file_extension": ".c++", 230 | "mimetype": "text/x-c++src", 231 | "name": "c++" 232 | } 233 | }, 234 | "nbformat": 4, 235 | "nbformat_minor": 2 236 | } 237 | -------------------------------------------------------------------------------- /notebooks/pyclingexample.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Cling Magic!\n", 8 | "First, install the cling magic" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "from cling import cling" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "Now you can execute C++ statements, one at a time. Usually, it's a\n", 25 | "good idea to execute headers by themselves." 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "%%cling\n", 35 | "#include " 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "When you provide a cling magic cell, it starts a background cling interpreter. All subsequent\n", 43 | "uses of cling magic sends commands to that same interpreter." 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "%%cling\n", 53 | "std::cout << \"magic!\" << std::endl;" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "## Communicating between Python and Cling\n", 61 | "If you define Python variables, you can send them to your c++ code. Anywhere\n", 62 | "the string {pythonvar} occurs, the C++ code will be replaced with the contents of the Python variable." 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "foo = \"world\"" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "%%cling\n", 81 | "// Note that \"baz\" is not defined by Python, but \"foo\" is.\n", 82 | "std::cout << \"Hello {foo} {baz}\" << std::endl;" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "You can also communicate from C++ to Python. To do this, provide a variable name\n", 90 | "on the same line as the \"%%cling\" statement." 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "%%cling\n", 100 | "int aa = 0;" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": null, 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "%%cling feedback\n", 110 | "aa = 3;\n", 111 | "std::cout << \"a=\" << aa << std::endl;" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "from cling import results\n", 121 | "print(results['feedback'])" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "## Replay\n", 129 | "It may happen that you kill your session by causing a segfault." 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "%%cling\n", 139 | "int *ptr = 0;\n", 140 | "ptr[0]=1;" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "In this case, you can replay all the commands prior to the segfault." 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": null, 153 | "metadata": {}, 154 | "outputs": [], 155 | "source": [ 156 | "from cling import replay\n", 157 | "replay()" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "%%cling\n", 167 | "std::cout << \"aa=\" << aa << std::endl;" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "The \"--init\" option forces the cling kernel to restart, wiping out all history." 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "%%cling --init\n", 184 | "#include " 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": null, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "%%cling\n", 194 | "std::string aa = \"new value\";" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": null, 200 | "metadata": {}, 201 | "outputs": [], 202 | "source": [ 203 | "%%cling\n", 204 | "\n", 205 | "#include \n", 206 | "#include \n", 207 | "\n", 208 | "// The Fibonacci function written using hpx async\n", 209 | "int fib(int n) {\n", 210 | " if(n < 2) return n;\n", 211 | " \n", 212 | " // launch a thread\n", 213 | " hpx::future f1 = hpx::async(hpx::launch::async, fib,n-1);\n", 214 | " \n", 215 | " // do work while the thread is running\n", 216 | " int f2 = fib(n-2);\n", 217 | " \n", 218 | " // wait for the thread to complete\n", 219 | " return f1.get() + f2;\n", 220 | "}" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": null, 226 | "metadata": {}, 227 | "outputs": [], 228 | "source": [ 229 | "%%cling\n", 230 | "{\n", 231 | " // Don't leave n in the namespace\n", 232 | " int n=10;\n", 233 | " std::cout << \"fib(\" << n << \")=\" << fib(n) << std::endl;\n", 234 | "}" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [] 243 | } 244 | ], 245 | "metadata": { 246 | "kernelspec": { 247 | "display_name": "Python 3 (ipykernel)", 248 | "language": "python", 249 | "name": "python3" 250 | }, 251 | "language_info": { 252 | "codemirror_mode": { 253 | "name": "ipython", 254 | "version": 3 255 | }, 256 | "file_extension": ".py", 257 | "mimetype": "text/x-python", 258 | "name": "python", 259 | "nbconvert_exporter": "python", 260 | "pygments_lexer": "ipython3", 261 | "version": "3.10.12" 262 | } 263 | }, 264 | "nbformat": 4, 265 | "nbformat_minor": 4 266 | } 267 | -------------------------------------------------------------------------------- /bot/cxxbot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # pylint: disable=W0613, C0116 3 | # type: ignore[union-attr] 4 | # This program is dedicated to the public domain under the CC0 license. 5 | # pip3 install python-telegram-bot 6 | 7 | """ 8 | Simple Bot to reply to Telegram messages. 9 | 10 | First, a few handler functions are defined. Then, those functions are passed to 11 | the Dispatcher and registered at their respective places. 12 | Then, the bot is started and runs until we press Ctrl-C on the command line. 13 | """ 14 | 15 | from subprocess import Popen, PIPE 16 | from traceback import print_exc 17 | 18 | import telecling 19 | from time import sleep, time 20 | import datetime 21 | 22 | import logging 23 | import re 24 | import os 25 | from signal import SIGINT 26 | 27 | from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackContext 28 | from telegram import Update 29 | 30 | from teleplot import plotjson 31 | from colored import colored 32 | 33 | pwd_dir = os.path.join(os.environ["HOME"],"cxxcodes") 34 | time_limit = 24*60*60*7 # one week 35 | 36 | # Enable logging 37 | logging.basicConfig( 38 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO 39 | ) 40 | 41 | def mtime(fname): 42 | return time() - os.path.getmtime(fname) 43 | 44 | logger = logging.getLogger(__name__) 45 | 46 | def get_image(fname): 47 | with open(fname, "rb") as fd: 48 | return fd.read() 49 | 50 | class Shutdown: 51 | def __init__(self, pid): 52 | self.pid = pid 53 | def end(self): 54 | os.kill(self.pid, SIGINT) 55 | 56 | shutdown = Shutdown(os.getpid()) 57 | 58 | def shorten(text): 59 | if len(text) > 4000: 60 | return text[:4000]+"..." 61 | return text 62 | 63 | def msg(update, text): 64 | try: 65 | try: 66 | image = plotjson(text.strip()) 67 | except: 68 | image = None 69 | if image is not None: 70 | with open(image, "rb") as fd: 71 | update.message.reply_photo(fd) 72 | os.remove(image) 73 | elif re.search(r'', text): 74 | update.message.reply_html(shorten(text)) 75 | else: 76 | update.message.reply_text(shorten(text)) 77 | except: 78 | print(colored("FATAL EXCEPTION","red")) 79 | print_exc() 80 | shutdown.end() 81 | 82 | def photo(update, fname): 83 | try: 84 | with open(fname, "rb") as fd: 85 | update.message.reply_photo(fd) 86 | except: 87 | print_exc() 88 | shutdown.end() 89 | 90 | def start(update: Update, context: CallbackContext) -> None: 91 | from_user = update.message.from_user 92 | username = from_user.username 93 | msg(update, 'Hello, @%s!' % username) 94 | 95 | 96 | def help_command(update: Update, context: CallbackContext) -> None: 97 | msg(update, "Send code to the cling server for evaluation") 98 | 99 | clients = {} 100 | 101 | def cmdproc(update: Update, context: CallbackContext) -> None: 102 | code = update.message.text 103 | user = update.effective_user 104 | from_user = update.message.from_user 105 | username = from_user.username 106 | 107 | if username not in clients: 108 | g = re.match(r'(\w{3,100}):(\w{3,100})', code.strip()) 109 | if g: 110 | fname = os.path.join(pwd_dir, g.group(1)+".txt") 111 | if os.path.exists(fname): 112 | mt = mtime(fname) 113 | with open(fname, "r") as fd: 114 | contents = fd.read().strip() 115 | if mt > time_limit: 116 | msg(update, "Password expired") 117 | elif contents == g.group(2): 118 | clients[username] = telecling.ClingServer() 119 | msg(update, "Password Approved") 120 | photo(update, "thumbsup.png") 121 | else: 122 | sleep(5) 123 | print('"%s" != "%s"' % (contents, g.group(2))) 124 | msg(update, "Password Failed") 125 | else: 126 | msg(update, "Password Failed, file does not exist: %s" % fname) 127 | else: 128 | msg(update, "Please enter a valid password") 129 | else: 130 | server = clients[username] 131 | res = server.exec_code(code) 132 | reply_made = False 133 | msg(update, "Out[%d]" % server.count) 134 | for message in res: 135 | if len(message.strip())==0: 136 | continue 137 | msg(update, message) 138 | reply_made = True 139 | if not reply_made: 140 | msg(update, "OK") 141 | #photo(update, "thumbsup.png") 142 | #help(context.bot.send_photo) #(chat_id=update.effective_chat.id, photo=thumbs_up) 143 | 144 | 145 | def main(): 146 | """Start the bot.""" 147 | valid_users = 0 148 | os.makedirs(pwd_dir, exist_ok=True) 149 | print("Determining if there any valid user logins...") 150 | for fname in os.listdir(pwd_dir): 151 | full = os.path.join(pwd_dir, fname) 152 | if not full.endswith(".txt"): 153 | print(colored(f"Skipping '{fname}' because it does not end in .txt","red")) 154 | continue 155 | if mtime(full) > time_limit: 156 | print(colored(f"Skipping '{fname}' because it is expired","red")) 157 | continue 158 | if (os.stat(full).st_mode & 0o66) != 0: 159 | print(colored(f"Skipping '{fname}' because it is readable by others.","red")) 160 | continue 161 | c = open(full,"r").read() 162 | if not re.match(r"^\w{3,100}$", c.strip()): 163 | print(colored(f"Skipping '{fname}' because the contents are invalid","red")) 164 | continue 165 | print(colored("A valid user login was found!","green")) 166 | valid_users += 1 167 | break 168 | if valid_users == 0: 169 | print(colored(f"No valid users are present in {pwd_dir}.","red")) 170 | print(f""" 171 | To create a valid user, create a file named ~/cxxcodes/username.txt that contains 172 | a password consisting of letters, numbers, or the underscore. For help in inventing 173 | passwords, please try the following. 174 | 175 | pip3 install --user randpass 176 | randpass -n 1 -o ~/cxxcodes/username.txt MND 177 | """) 178 | exit(1) 179 | print() 180 | print("Checking for a bot app token...") 181 | token = os.environ.get("CXXBOT_TOKEN", None) 182 | if token is None: 183 | print(colored("No valid token found.","red")) 184 | print(""" 185 | In order to use the bot, you must create a bot and get it's token from the BotFather 186 | (a special Telegram user id). Once you have it,Please set the CXXBOT_TOKEN environment variable 187 | with that token.""") 188 | exit(3) 189 | print(colored("Token found! Starting up. Use Ctrl-C to shut down.","green")) 190 | print() 191 | updater = Updater(token, use_context=True) 192 | 193 | # Get the dispatcher to register handlers 194 | dispatcher = updater.dispatcher 195 | 196 | # on different commands - answer in Telegram 197 | dispatcher.add_handler(CommandHandler("start", start)) 198 | dispatcher.add_handler(CommandHandler("help", help_command)) 199 | 200 | dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, cmdproc)) 201 | 202 | # Start the Bot 203 | updater.start_polling() 204 | 205 | # Run the bot until you press Ctrl-C or the process receives SIGINT, 206 | # SIGTERM or SIGABRT. This should be used most of the time, since 207 | # start_polling() is non-blocking and will stop the bot gracefully. 208 | updater.idle() 209 | 210 | 211 | if __name__ == '__main__': 212 | main() 213 | -------------------------------------------------------------------------------- /run_hpx.cpp: -------------------------------------------------------------------------------- 1 | #ifndef RUN_HPX_CPP 2 | #define RUN_HPX_CPP 3 | // Copyright (c) 2016 Hartmut Kaiser 4 | // 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | // This example demonstrates several things: 9 | // 10 | // - How to initialize (and terminate) the HPX runtime from a global object 11 | // (see the type `manage_global_runtime' below) 12 | // - How to register and unregister any (kernel) thread with the HPX runtime 13 | // - How to launch an HPX thread from any (registered) kernel thread and 14 | // how to wait for the HPX thread to run to completion before continuing. 15 | // Any value returned from the HPX thread will be marshaled back to the 16 | // calling (kernel) thread. 17 | // 18 | // This scheme is generally useful if HPX should be initialized from a shared 19 | // library and the main executable might not even be aware of this. 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace hpx_global { 31 | 32 | /////////////////////////////////////////////////////////////////////////////// 33 | // Store the command line arguments in global variables to make them available 34 | // to the startup code. 35 | 36 | #if defined(linux) || defined(__linux) || defined(__linux__) 37 | 38 | int __argc = 1; 39 | char __arg0__[] { "jupytercling" }; 40 | char* __argv__[] {(char*)__arg0__,0}; 41 | char** __argv = (char**)__argv__; 42 | 43 | void set_argv_argv(int argc, char* argv[], char* env[]) 44 | { 45 | //__argc = argc; 46 | //__argv = argv; 47 | } 48 | 49 | __attribute__((section(".init_array"))) 50 | void (*set_global_argc_argv)(int, char*[], char*[]) = &set_argv_argv; 51 | 52 | #elif defined(__APPLE__) 53 | 54 | #include 55 | 56 | inline int get_arraylen(char** argv) 57 | { 58 | int count = 0; 59 | if (nullptr != argv) 60 | { 61 | while(nullptr != argv[count]) 62 | ++count; 63 | } 64 | return count; 65 | } 66 | 67 | #error "Bad" 68 | int __argc = get_arraylen(*_NSGetArgv()); 69 | char** __argv = *_NSGetArgv(); 70 | 71 | #endif 72 | 73 | /////////////////////////////////////////////////////////////////////////////// 74 | // This class demonstrates how to initialize a console instance of HPX 75 | // (locality 0). In order to create an HPX instance which connects to a running 76 | // HPX application two changes have to be made: 77 | // 78 | // - replace hpx::runtime_mode_console with hpx::runtime_mode_connect 79 | // - replace hpx::finalize() with hpx::disconnect() 80 | // 81 | struct manage_global_runtime 82 | { 83 | manage_global_runtime(int nth) 84 | : running_(false), rts_(nullptr) 85 | { 86 | #if defined(HPX_WINDOWS) 87 | hpx::detail::init_winsocket(); 88 | #endif 89 | 90 | std::ostringstream thread_spec; 91 | thread_spec << "--hpx:threads=" << nth; 92 | std::vector const cfg = { 93 | // make sure hpx_main is always executed 94 | "hpx.run_hpx_main!=1", 95 | thread_spec.str().c_str(), 96 | // allow for unknown command line options 97 | "hpx.commandline.allow_unknown!=1", 98 | // disable HPX' short options 99 | "hpx.commandline.aliasing!=0", 100 | "hpx.stacks.small_size=0x160000" 101 | }; 102 | 103 | using hpx::util::placeholders::_1; 104 | using hpx::util::placeholders::_2; 105 | hpx::util::function_nonser start_function = 106 | hpx::util::bind(&manage_global_runtime::hpx_main, this, _1, _2); 107 | 108 | hpx::init_params init_args; 109 | init_args.cfg = cfg; 110 | init_args.mode = hpx::runtime_mode::default_; 111 | 112 | if (!hpx::start(start_function, __argc, __argv, init_args)) 113 | //if (!hpx::start(start_function, __argc, __argv, cfg, hpx::runtime_mode::console)) 114 | { 115 | // Something went wrong while initializing the runtime. 116 | // This early we can't generate any output, just bail out. 117 | std::abort(); 118 | } 119 | 120 | // Wait for the main HPX thread (hpx_main below) to have started running 121 | std::unique_lock lk(startup_mtx_); 122 | while (!running_) 123 | startup_cond_.wait(lk); 124 | } 125 | 126 | ~manage_global_runtime() 127 | { 128 | // notify hpx_main above to tear down the runtime 129 | { 130 | std::lock_guard lk(mtx_); 131 | rts_ = nullptr; // reset pointer 132 | } 133 | 134 | cond_.notify_one(); // signal exit 135 | 136 | // wait for the runtime to exit 137 | hpx::stop(); 138 | } 139 | 140 | // registration of external (to HPX) threads 141 | void register_thread(const char *name) 142 | { 143 | hpx::register_thread(rts_, name); 144 | } 145 | void unregister_thread() 146 | { 147 | hpx::unregister_thread(rts_); 148 | } 149 | 150 | protected: 151 | // Main HPX thread, does nothing but wait for the application to exit 152 | int hpx_main(int argc, char* argv[]) 153 | { 154 | // Store a pointer to the runtime here. 155 | rts_ = hpx::get_runtime_ptr(); 156 | 157 | // Signal to constructor that thread has started running. 158 | { 159 | std::lock_guard lk(startup_mtx_); 160 | running_ = true; 161 | } 162 | 163 | startup_cond_.notify_one(); 164 | 165 | // Here other HPX specific functionality could be invoked... 166 | 167 | // Now, wait for destructor to be called. 168 | { 169 | std::unique_lock lk(mtx_); 170 | if (rts_ != nullptr) 171 | cond_.wait(lk); 172 | } 173 | 174 | // tell the runtime it's ok to exit 175 | return hpx::finalize(); 176 | } 177 | 178 | private: 179 | hpx::lcos::local::spinlock mtx_; 180 | hpx::lcos::local::condition_variable_any cond_; 181 | 182 | std::mutex startup_mtx_; 183 | std::condition_variable startup_cond_; 184 | bool running_; 185 | 186 | hpx::runtime* rts_; 187 | }; 188 | 189 | // This global object will initialize HPX in its constructor and make sure HPX 190 | // stops running in its destructor. 191 | manage_global_runtime *init = nullptr;//new manage_global_runtime;//nullptr; 192 | 193 | int next_id_seq = 1; 194 | //char next_id_buf[5]; 195 | std::string next_id() { 196 | //sprintf(next_id_buf,"id=%d",next_id_seq++); 197 | std::ostringstream buf; 198 | buf << "id=" << next_id_seq++; 199 | return std::move(buf.str()); 200 | } 201 | 202 | /////////////////////////////////////////////////////////////////////////////// 203 | struct thread_registration_wrapper 204 | { 205 | thread_registration_wrapper(const char *name) 206 | { 207 | // Register this thread with HPX, this should be done once for 208 | // each external OS-thread intended to invoke HPX functionality. 209 | // Calling this function more than once will silently fail (will 210 | // return false). 211 | init->register_thread(name); 212 | } 213 | ~thread_registration_wrapper() 214 | { 215 | // Unregister the thread from HPX, this should be done once in the 216 | // end before the external thread exists. 217 | init->unregister_thread(); 218 | } 219 | }; 220 | 221 | /////////////////////////////////////////////////////////////////////////////// 222 | 223 | void submit_work(int nth,std::function work_item) { 224 | if(init == nullptr) 225 | init = new manage_global_runtime(nth); 226 | std::string id = next_id(); 227 | std::function hpx_work_item = [&](){ 228 | thread_registration_wrapper register_thread(id.c_str()); 229 | hpx::threads::run_as_hpx_thread(work_item); 230 | }; 231 | std::thread t(hpx_work_item); 232 | t.join(); 233 | delete init; 234 | init = nullptr; 235 | } 236 | 237 | }; 238 | 239 | const int run_hpx_threads = 4; 240 | 241 | template 242 | typename std::result_of::type run_hpx(F f) { 243 | if constexpr(std::is_same::type,void>::value) { 244 | hpx_global::submit_work(run_hpx_threads, f); 245 | } else { 246 | typename std::result_of::type r; 247 | hpx_global::submit_work(run_hpx_threads, [&r,&f](){ 248 | r = f(); 249 | }); 250 | return std::move(r); 251 | } 252 | } 253 | #endif 254 | -------------------------------------------------------------------------------- /Kernel.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // CLING - the C++ LLVM-based InterpreterG :) 3 | // author: Axel Naumann 4 | // 5 | // This file is dual-licensed: you can choose to license it under the University 6 | // of Illinois Open Source License or the GNU Lesser General Public License. See 7 | // LICENSE.TXT for details. 8 | //------------------------------------------------------------------------------ 9 | 10 | // FIXME: This file shall contain the decl of cling::Jupyter in a future 11 | // revision! 12 | //#include "cling/Interpreter/Jupyter/Kernel.h" 13 | 14 | #include "cling/Interpreter/Interpreter.h" 15 | #include "cling/Interpreter/Value.h" 16 | #include "cling/MetaProcessor/MetaProcessor.h" 17 | #include "cling/Utils/Output.h" 18 | 19 | #include "cling/Interpreter/Exception.h" 20 | #include "llvm/Support/raw_ostream.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #ifndef _WIN32 33 | # include 34 | #else 35 | # include 36 | # define write _write 37 | #endif 38 | 39 | // FIXME: should be moved into a Jupyter interp struct that then gets returned 40 | // from create. 41 | int pipeToJupyterFD = -1; 42 | 43 | namespace cling { 44 | namespace Jupyter { 45 | struct MIMEDataRef { 46 | const char* m_Data; 47 | const long m_Size; 48 | 49 | MIMEDataRef(const std::string& str): 50 | m_Data(str.c_str()), m_Size((long)str.length() + 1) {} 51 | MIMEDataRef(const char* str): 52 | MIMEDataRef(std::string(str)) {} 53 | MIMEDataRef(const char* data, long size): 54 | m_Data(data), m_Size(size) {} 55 | }; 56 | 57 | /// Push MIME stuff to Jupyter. To be called from user code. 58 | ///\param contentDict - dictionary of MIME type versus content. E.g. 59 | /// {{"text/html", {"
", }} 60 | ///\returns `false` if the output could not be sent. 61 | bool pushOutput(const std::map contentDict) { 62 | 63 | // Pipe sees (all numbers are longs, except for the first: 64 | // - num bytes in a long (sent as a single unsigned char!) 65 | // - num elements of the MIME dictionary; Jupyter selects one to display. 66 | // For each MIME dictionary element: 67 | // - size of MIME type string (including the terminating 0) 68 | // - MIME type as 0-terminated string 69 | // - size of MIME data buffer (including the terminating 0 for 70 | // 0-terminated strings) 71 | // - MIME data buffer 72 | 73 | // Write number of dictionary elements (and the size of that number in a 74 | // char) 75 | unsigned char sizeLong = sizeof(long); 76 | if (write(pipeToJupyterFD, &sizeLong, 1) != 1) 77 | return false; 78 | long dictSize = contentDict.size(); 79 | if (write(pipeToJupyterFD, &dictSize, sizeof(long)) != sizeof(long)) 80 | return false; 81 | 82 | for (auto iContent: contentDict) { 83 | const std::string& mimeType = iContent.first; 84 | long mimeTypeSize = (long)mimeType.size(); 85 | if (write(pipeToJupyterFD, &mimeTypeSize, sizeof(long)) != sizeof(long)) 86 | return false; 87 | if (write(pipeToJupyterFD, mimeType.c_str(), mimeType.size() + 1) 88 | != (long)(mimeType.size() + 1)) 89 | return false; 90 | const MIMEDataRef& mimeData = iContent.second; 91 | if (write(pipeToJupyterFD, &mimeData.m_Size, sizeof(long)) 92 | != sizeof(long)) 93 | return false; 94 | if (write(pipeToJupyterFD, mimeData.m_Data, mimeData.m_Size) 95 | != mimeData.m_Size) 96 | return false; 97 | } 98 | return true; 99 | } 100 | } // namespace Jupyter 101 | } // namespace cling 102 | 103 | extern "C" { 104 | ///\{ 105 | ///\name Cling4CTypes 106 | /// The Python compatible view of cling 107 | 108 | /// The MetaProcessor cast to void* 109 | using TheMetaProcessor = void; 110 | 111 | /// Create an interpreter object. 112 | TheMetaProcessor* 113 | cling_create(int argc, const char *argv[], const char* llvmdir, int pipefd) { 114 | pipeToJupyterFD = pipefd; 115 | auto I = new cling::Interpreter(argc, argv, llvmdir); 116 | return new cling::MetaProcessor(*I, cling::errs()); 117 | } 118 | 119 | 120 | /// Destroy the interpreter. 121 | void cling_destroy(TheMetaProcessor *metaProc) { 122 | cling::MetaProcessor *M = (cling::MetaProcessor*)metaProc; 123 | cling::Interpreter *I = const_cast(&M->getInterpreter()); 124 | delete M; 125 | delete I; 126 | } 127 | 128 | /// Stringify a cling::Value 129 | static std::string ValueToString(const cling::Value& V) { 130 | std::string valueString; 131 | { 132 | llvm::raw_string_ostream os(valueString); 133 | V.print(os); 134 | } 135 | return valueString; 136 | } 137 | 138 | const char *expr = ".expr"; 139 | const int nexpr = strlen(expr); 140 | int sequence = 0; 141 | 142 | /// Evaluate a string of code. Returns nullptr on failure. 143 | /// Returns a string representation of the expression (can be "") on success. 144 | char* cling_eval_inner(TheMetaProcessor *metaProc, const char *code,bool& good) { 145 | cling::MetaProcessor *M = (cling::MetaProcessor*)metaProc; 146 | cling::Value V; 147 | cling::Interpreter::CompilationResult Res; 148 | bool isExcept = false; 149 | try { 150 | good = 0; 151 | std::ostringstream cmd; 152 | std::ostringstream fname; 153 | fname << getenv("HOME") << "/.code" << (sequence++) << ".cc"; 154 | std::ofstream cfile(fname.str()); 155 | if(strncmp(code,expr,nexpr) == 0) { 156 | cfile << "struct __tmp__" << sequence << " {" << std::endl; 157 | 158 | // constructor 159 | cfile << "__tmp__" << sequence << " (){" << std::endl; 160 | cfile << "#ifdef WRAP_EXPR" << std::endl; 161 | cfile << "WRAP_EXPR(init();)" << std::endl; 162 | cfile << "#else" << std::endl; 163 | cfile << "init();" << std::endl; 164 | cfile << "#endif" << std::endl; 165 | cfile << "}" << std::endl; 166 | 167 | cfile << "static void init() {" << std::endl; 168 | cfile << (code+nexpr) << std::endl; 169 | cfile << "}" << std::endl; 170 | 171 | cfile << "} __tmp__instance__" << sequence << ";" << std::endl; 172 | } else { 173 | cfile << code << std::endl; 174 | } 175 | cfile.close(); 176 | cmd << ".L " << fname.str(); 177 | std::string cmdstr = cmd.str(); 178 | if (M->process(cmdstr.c_str(), Res, &V, /*disableValuePrinting*/ true)) { 179 | //cling::Jupyter::pushOutput({{"text/html", "Incomplete input! Ignored."}}); 180 | std::cout << "Incomplete input! Ignored." << std::endl; 181 | M->cancelContinuation(); 182 | return nullptr; 183 | } 184 | std::string fstr = fname.str(); 185 | //unlink(fstr.c_str()); 186 | good = (Res == 0); 187 | } 188 | catch(cling::InterpreterException& e) { 189 | //std::string output (strcat("Caught an interpreter exception:", e.what().c_str())) ; 190 | std::string output ("Caught an interpreter exception:"); 191 | output += e.what(); 192 | cling::Jupyter::pushOutput({{"text/html", output}}); 193 | isExcept = true; 194 | } 195 | catch(std::exception& e) { 196 | //std::string output(strcat("Caught a standard exception:" , e.what().c_str())) ; 197 | std::string output("Caught a standard exception:") ; 198 | output += e.what(); 199 | cling::Jupyter::pushOutput({{"text/html", output}}); 200 | isExcept = true; 201 | } 202 | catch(...) { 203 | std::string output = "Exception occurred. Recovering...\n"; 204 | cling::Jupyter::pushOutput({{"text/html", output}}); 205 | isExcept = true; 206 | } 207 | 208 | if (isExcept) { 209 | return nullptr; 210 | } 211 | 212 | if (Res != cling::Interpreter::kSuccess) 213 | return nullptr; 214 | 215 | if (!V.isValid()) 216 | return strdup(""); 217 | return strdup(ValueToString(V).c_str()); 218 | } 219 | 220 | #include 221 | 222 | void cling_eval_free(char* str) { 223 | free(str); 224 | } 225 | 226 | /// Code completion interfaces. 227 | 228 | /// Start completion of code. Returns a handle to be passed to 229 | /// cling_complete_next() to iterate over the completion options. Returns nulptr 230 | /// if no completions are known. 231 | void* cling_complete_start(const char* code) { 232 | return new int(42); 233 | } 234 | 235 | /// Grab the next completion of some code. Returns nullptr if none is left. 236 | const char* cling_complete_next(void* completionHandle) { 237 | int* counter = (int*) completionHandle; 238 | if (++(*counter) > 43) { 239 | delete counter; 240 | return nullptr; 241 | } 242 | return "COMPLETE!"; 243 | } 244 | 245 | ///\} 246 | 247 | } // extern "C" 248 | -------------------------------------------------------------------------------- /notebooks/Lecture2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "

Lecture 2

" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "

Random numbers

" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "#include \n", 24 | "#include \n", 25 | "#include " 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "// Use the current time as a random seed\n", 35 | "std::srand(std::time(0));\n", 36 | "// Get one random number\n", 37 | "int random_variable = std::rand();\n", 38 | "std::cout\n", 39 | " << \" Random value on [0 \" << RAND_MAX << \"]: \"\n", 40 | " << random_variable << '\\n';" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "

Uniform distributed random numbers

" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "#include " 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | ".expr\n", 66 | "// Generate a random number device\n", 67 | "std::random_device rd;\n", 68 | "// Set the standard mersenne_twister_engine\n", 69 | "std::mt19937 gen(rd ());\n", 70 | "// Specify the interval [1 ,6]\n", 71 | "std::uniform_int_distribution dis (1, 6);\n", 72 | "// Specifiy the interval [1.0 ,6.0]\n", 73 | "std::uniform_real_distribution disd (1 ,6);\n", 74 | "std::cout << dis(gen) << \" \" << disd(gen) << '\\n';" 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "

Computation of the average

" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "#include \n", 91 | "#include " 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "%%writefile numbers.txt\n", 101 | "3\n", 102 | "4\n", 103 | "87\n", 104 | "-20" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | ".expr\n", 114 | "double sum = 0;\n", 115 | "size_t count = 0;\n", 116 | "double x = 0;\n", 117 | "std::ifstream fin(\"numbers.txt\");\n", 118 | "while (fin >> x)\n", 119 | "{\n", 120 | " sum += x;\n", 121 | " ++ count;\n", 122 | "}\n", 123 | "std::cout << \" Average : \"\n", 124 | " << std::setprecision (3)\n", 125 | " << sum / count << std :: endl;" 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": {}, 131 | "source": [ 132 | "

Advanced computing of the average

" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": null, 138 | "metadata": {}, 139 | "outputs": [], 140 | "source": [ 141 | "#include \n", 142 | "#include " 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "std::vector values;" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": null, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | ".expr\n", 161 | "double x;\n", 162 | "std::ifstream fin(\"numbers.txt\");\n", 163 | "while (fin >> x)\n", 164 | "{\n", 165 | " values.push_back (x);\n", 166 | "}\n", 167 | "double sum =\n", 168 | " std::accumulate( values.begin (), values.end (), 0.0f);\n", 169 | "std::cout << \" Average : \"\n", 170 | " << sum / values .size () << std :: endl;" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "

Looping over a vector

" 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": {}, 183 | "source": [ 184 | "

Long form

" 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": null, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | ".expr\n", 194 | "for( size_t i = 0; i < values.size () ; i++)\n", 195 | "{\n", 196 | " values[i] *= 2;\n", 197 | " std::cout << values[i] << std::endl;\n", 198 | "}" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "

Short form

" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [ 214 | ".expr\n", 215 | "for(auto& v : values) {\n", 216 | " v *= 2;\n", 217 | " std::cout << v << std::endl;\n", 218 | "}" 219 | ] 220 | }, 221 | { 222 | "cell_type": "markdown", 223 | "metadata": {}, 224 | "source": [ 225 | "

Computing the median

" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": null, 231 | "metadata": {}, 232 | "outputs": [], 233 | "source": [ 234 | "typedef std::vector::size_type vec_sz ;" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [ 243 | ".expr\n", 244 | "vec_sz size = values.size();\n", 245 | "double median = 0;\n", 246 | "vec_sz mid = size/2;\n", 247 | "if( size % 2 == 0 )\n", 248 | " median = 0.5*( values[mid] + values[mid -1]);\n", 249 | "else\n", 250 | " median = values [mid];\n", 251 | "std::cout << \"median:\" << median << std::endl;" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": null, 257 | "metadata": {}, 258 | "outputs": [], 259 | "source": [ 260 | "#include " 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": null, 266 | "metadata": {}, 267 | "outputs": [], 268 | "source": [ 269 | ".expr\n", 270 | "double x;\n", 271 | "std::ifstream fin(\"numbers.txt\");\n", 272 | "while (fin >> x)\n", 273 | "{\n", 274 | " values.push_back(x);\n", 275 | "}\n", 276 | "std::sort( values.begin (), values.end ());\n", 277 | "vec_sz mid = values .size () / 2;\n", 278 | "double median = values .size () % 2 == 0 ?\n", 279 | " 0.5*( values [mid ]+ values [mid -1]) : values [mid ];\n", 280 | "std::cout << \" Median : \"\n", 281 | " << median << std :: endl;" 282 | ] 283 | }, 284 | { 285 | "cell_type": "markdown", 286 | "metadata": {}, 287 | "source": [ 288 | "

Functions

" 289 | ] 290 | }, 291 | { 292 | "cell_type": "markdown", 293 | "metadata": {}, 294 | "source": [ 295 | "

Example: maximum

" 296 | ] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": null, 301 | "metadata": {}, 302 | "outputs": [], 303 | "source": [ 304 | "int max(int a, int b)\n", 305 | "{\n", 306 | " return a>b?a:b;\n", 307 | "}" 308 | ] 309 | }, 310 | { 311 | "cell_type": "markdown", 312 | "metadata": {}, 313 | "source": [ 314 | "

Function definition for the median

" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": null, 320 | "metadata": {}, 321 | "outputs": [], 322 | "source": [ 323 | "double median_func (std :: vector values )\n", 324 | "{\n", 325 | " std::sort(values.begin(), values.end ());\n", 326 | " vec_sz mid = values.size () / 2;\n", 327 | " double res = values.size () % 2 == 0 ?\n", 328 | " 0.5*( values [mid] + values [mid-1]) : values [mid ];\n", 329 | " return res;\n", 330 | "}" 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": null, 336 | "metadata": {}, 337 | "outputs": [], 338 | "source": [ 339 | "std::cout << median_func(values) << std::endl;" 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": null, 345 | "metadata": {}, 346 | "outputs": [], 347 | "source": [] 348 | } 349 | ], 350 | "metadata": { 351 | "kernelspec": { 352 | "display_name": "C++17", 353 | "language": "C++", 354 | "name": "cling-cpp17" 355 | }, 356 | "language_info": { 357 | "codemirror_mode": "c++", 358 | "file_extension": ".c++", 359 | "mimetype": "text/x-c++src", 360 | "name": "c++" 361 | } 362 | }, 363 | "nbformat": 4, 364 | "nbformat_minor": 4 365 | } 366 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # FROM fedora:33 2 | #RUN dnf install -y gcc-c++ gcc make git \ 3 | # bzip2 hwloc-devel blas blas-devel lapack lapack-devel boost-devel \ 4 | # libatomic which vim-enhanced wget zlib-devel cmake \ 5 | # python3-flake8 gdb sudo python3 python3-pip openmpi-devel sqlite-devel sqlite \ 6 | # findutils openssl-devel papi papi-devel lm_sensors-devel tbb-devel \ 7 | # xz bzip2 patch flex openssh-server \ 8 | # texlive-xetex texlive-bibtex texlive-adjustbox texlive-caption texlive-collectbox \ 9 | # texlive-enumitem texlive-environ texlive-eurosym texlive-jknapltx texlive-parskip \ 10 | # texlive-pgf texlive-rsfs texlive-tcolorbox texlive-titling texlive-trimspaces \ 11 | # texlive-ucs texlive-ulem texlive-upquote texlive-latex pandoc 12 | FROM ubuntu:22.04 13 | ENV DEBIAN_FRONTEND noninteractive 14 | RUN apt update -y && apt install -y bzip2 libhwloc-dev vim git gdb python3 python3-pip \ 15 | libpapi-dev patch cmake libblas-dev liblapack-dev libtbb-dev patch npm \ 16 | libboost-dev libboost-filesystem-dev \ 17 | && apt clean 18 | 19 | ARG CPUS 20 | ARG BUILD_TYPE 21 | 22 | WORKDIR / 23 | ## ENV GCC_VER 8.4.0 24 | ## COPY install-from-spack.sh /usr/local/bin 25 | ## RUN bash /usr/local/bin/install-from-spack.sh 26 | ## COPY alternatives.sh /usr/local/bin 27 | ## RUN bash /usr/local/bin/alternatives.sh 28 | 29 | # ENV AH_VER 4.6.0 30 | # RUN curl -kLO https://www.dyninst.org/sites/default/files/downloads/harmony/ah-${AH_VER}.tar.gz 31 | # RUN tar -xzf ah-${AH_VER}.tar.gz 32 | # WORKDIR /activeharmony-${AH_VER} 33 | # COPY ./activeharmony-4.6.0/code-server/code_generator.cxx code-server/code_generator.cxx 34 | # RUN make CFLAGS=-fPIC LDFLAGS=-fPIC && make install prefix=/usr/local/activeharmony 35 | 36 | # ENV OTF2_VER 2.1.1 37 | # WORKDIR / 38 | # RUN curl -kLO https://www.vi-hps.org/cms/upload/packages/otf2/otf2-${OTF2_VER}.tar.gz 39 | # RUN tar -xzf otf2-${OTF2_VER}.tar.gz 40 | # WORKDIR otf2-${OTF2_VER} 41 | # RUN ./configure --prefix=/usr/local/otf2 --enable-shared && make && make install 42 | 43 | #RUN ln -s /usr/lib64/openmpi/lib/libmpi_cxx.so /usr/lib64/openmpi/lib/libmpi_cxx.so.1 44 | #RUN ln -s /usr/lib64/openmpi/lib/libmpi.so /usr/lib64/openmpi/lib/libmpi.so.12 45 | 46 | #ENV PYVER 3.6.8 47 | #WORKDIR / 48 | #RUN wget https://www.python.org/ftp/python/${PYVER}/Python-${PYVER}.tgz 49 | #RUN tar xf Python-${PYVER}.tgz 50 | #WORKDIR /Python-${PYVER} 51 | #RUN ./configure 52 | #RUN make -j ${CPUS} install 53 | 54 | ## Make headers available 55 | #RUN cp /Python-${PYVER}/pyconfig.h /Python-${PYVER}/Include 56 | #RUN ln -s /Python-${PYVER}/Include /usr/include/python${PYVER} 57 | 58 | #RUN pip3 install --trusted-host pypi.org --trusted-host files.pythonhosted.org numpy tensorflow keras CNTK pytest 59 | #RUN pip3 install numpy tensorflow keras CNTK pytest 60 | WORKDIR / 61 | 62 | #RUN dnf install -y python3-devel 63 | 64 | WORKDIR / 65 | RUN git clone --depth 1 https://github.com/pybind/pybind11.git && \ 66 | mkdir -p /pybind11/build && \ 67 | cd /pybind11/build && \ 68 | cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DPYBIND11_PYTHON_VERSION=${PYVER} .. && \ 69 | make -j ${CPUS} install && \ 70 | rm -f $(find . -name \*.o) 71 | 72 | RUN git clone --depth 1 https://bitbucket.org/blaze-lib/blaze.git && \ 73 | cd /blaze && \ 74 | mkdir -p /blaze/build && \ 75 | cd /blaze/build && \ 76 | cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .. && \ 77 | make -j ${CPUS} install && \ 78 | rm -f $(find . -name \*.o) 79 | 80 | RUN git clone --depth 1 https://github.com/STEllAR-GROUP/blaze_tensor.git && \ 81 | mkdir -p /blaze_tensor/build && \ 82 | cd /blaze_tensor/build && \ 83 | cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .. && \ 84 | make -j ${CPUS} install && \ 85 | rm -f $(find . -name \*.o) 86 | 87 | WORKDIR /etc/skel 88 | COPY ./notebooks/*.ipynb ./ 89 | #RUN git clone --depth 1 https://github.com/shortcourse/USACM16-shortcourse 90 | RUN git clone --depth 1 https://github.com/shortcourse/WCCM-APCOM-22 91 | RUN find . | xargs -d '\n' chmod +r 92 | 93 | RUN useradd -m jovyan -s /bin/bash 94 | USER jovyan 95 | WORKDIR /home/jovyan 96 | ENV LD_LIBRARY_PATH /home/jovyan/install/phylanx/lib64:/usr/local/lib64:/home/jovyan/install/phylanx/lib/phylanx:/usr/lib64/openmpi/lib 97 | USER root 98 | #RUN dnf install -y nodejs psmisc tbb-devel 99 | RUN pip3 install --upgrade pip 100 | RUN pip3 install jupyter==1.0.0 jupyterhub==1.0.0 matplotlib numpy termcolor 101 | 102 | ENV DATE 2020-03-10 103 | RUN mkdir -p /usr/install/cling 104 | WORKDIR /usr/install/cling 105 | RUN git clone --depth 1 --branch cling-patches http://root.cern.ch/git/llvm.git src 106 | WORKDIR /usr/install/cling/src/tools 107 | RUN git clone --depth 1 http://root.cern.ch/git/cling.git 108 | RUN git clone --depth 1 --branch cling-patches http://root.cern.ch/git/clang.git 109 | 110 | WORKDIR /usr/install/cling/src/tools/cling 111 | 112 | RUN mkdir -p /usr/install/cling/src/build 113 | COPY Pipe.hpp /usr/local/include/ 114 | #COPY Augment_Kernel.hpp /usr/local/include 115 | #COPY Kernel.cpp /usr/install/cling/src/tools/cling/tools/Jupyter 116 | 117 | WORKDIR /usr/install/cling/src/build 118 | RUN cmake -DCMAKE_INSTALL_PREFIX=/usr \ 119 | -DCMAKE_BUILD_TYPE=Release \ 120 | -DCMAKE_CXX_FLAGS='-Wl,-s -std=c++2a' \ 121 | -DLLVM_ENABLE_RTTI=ON \ 122 | -DLLVM_ENABLE_EH=ON \ 123 | /usr/install/cling/src 124 | # RUN dnf install -y patch 125 | WORKDIR /usr/install/cling/src 126 | COPY limits.patch . 127 | RUN patch -p1 < limits.patch 128 | WORKDIR /usr/install/cling/src/tools/cling 129 | COPY noexcept.patch ./ 130 | RUN patch -p1 < noexcept.patch 131 | WORKDIR /usr/install/cling/src/build 132 | COPY make.sh /usr/install/cling/src/build/ 133 | RUN bash ./make.sh 134 | RUN cd /usr/install/cling/src/tools/cling/tools/Jupyter/kernel && \ 135 | pip3 install -e . && \ 136 | jupyter-kernelspec install cling-cpp17 && \ 137 | npm install -g configurable-http-proxy 138 | WORKDIR /usr 139 | ## ENV CLING cling_2020-11-05_ROOT-fedora32 140 | ## ENV CLING_TARBALL ${CLING}.tar.bz2 141 | ## RUN curl -LO https://root.cern/download/cling/${CLING_TARBALL} && \ 142 | ## tar xjf ${CLING_TARBALL} && \ 143 | ## rm -f ${CLING_TARBALL} 144 | ## WORKDIR /usr/${CLING}/share/cling/Jupyter/kernel 145 | ## RUN pip3 install -e . && \ 146 | ## jupyter-kernelspec install cling-cpp17 && \ 147 | ## npm install -g configurable-http-proxy && \ 148 | ## ln -s /usr/${CLING}/bin/cling /usr/bin/cling 149 | 150 | RUN git clone -b 1.8.0 --depth 1 https://github.com/STEllAR-GROUP/hpx.git /hpx 151 | WORKDIR /hpx 152 | RUN mkdir -p /hpx/build 153 | WORKDIR /hpx/build 154 | #RUN env CXX=$(which clang++) cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 155 | RUN cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 156 | -DHPX_FILESYSTEM_WITH_BOOST_FILESYSTEM_COMPATIBILITY=ON \ 157 | -DHPX_WITH_CXX17_HARDWARE_DESTRUCTIVE_INTERFERENCE_SIZE=OFF \ 158 | -DHPX_WITH_FETCH_ASIO=ON \ 159 | -DHPX_WITH_BUILTIN_INTEGER_PACK=OFF \ 160 | -DHPX_WITH_ITTNOTIFY=OFF \ 161 | -DHPX_WITH_THREAD_COMPATIBILITY=ON \ 162 | -DHPX_WITH_MALLOC=system \ 163 | -DHPX_WITH_MORE_THAN_64_THREADS=ON \ 164 | -DHPX_WITH_MAX_CPU_COUNT=80 \ 165 | -DHPX_WITH_EXAMPLES=Off \ 166 | -DHPX_WITH_CXX_STANDARD=20 \ 167 | -DHPX_WITH_DATAPAR_BACKEND=STD_EXPERIMENTAL_SIMD \ 168 | .. && \ 169 | make -j ${CPUS} install && \ 170 | rm -f $(find . -name \*.o) 171 | 172 | ## RUN (make -j 8 install 2>&1 | tee make.out) 173 | COPY ./run_hpx.cpp /usr/include/run_hpx.cpp 174 | RUN chmod 644 /usr/include/run_hpx.cpp 175 | 176 | RUN pip3 install oauthenticator 177 | #RUN dnf install -y procps cppcheck python3-pycurl sqlite python3-libs 178 | COPY ./login.html /usr/local/share/jupyterhub/templates/login.html 179 | COPY ./login2.html /root 180 | COPY ./stellar-logo.png /usr/local/share/jupyterhub/static/images/ 181 | 182 | ENV PYTHONPATH /usr/local/python 183 | RUN mkdir -p /usr/local/python 184 | COPY ./mkuser.py ${PYTHONPATH}/mkuser.py 185 | COPY ./mkuser.py /usr/local/bin/mkuser 186 | RUN chmod 755 /usr/local/bin/mkuser 187 | RUN pip3 install tornado #==5.1.1 # There's a bug in newer versions 188 | COPY ./clingk.py /usr/${CLING}/share/cling/Jupyter/kernel/clingkernel.py 189 | RUN python3 -c 'import sys; print(sys.path[-1])' > /tmp/path.txt 190 | COPY ./pipes1.py ${PYTHONPATH}/ 191 | COPY ./pipes3.py ${PYTHONPATH}/ 192 | COPY ./cling.py ${PYTHONPATH}/ 193 | COPY ./py11.py ${PYTHONPATH}/ 194 | #RUN cp /Python-${PYVER}/pyconfig.h /Python-${PYVER}/Include 195 | #RUN ln -s /Python-${PYVER}/Include /usr/include/python${PYVER} 196 | WORKDIR / 197 | 198 | RUN git clone --depth 1 https://github.com/STEllAR-GROUP/BlazeIterative 199 | WORKDIR /BlazeIterative/build 200 | RUN cmake .. 201 | RUN make install 202 | 203 | # For some reason, HPX will not link in @py11() unless I do this 204 | RUN ldconfig /usr/local/lib64 205 | 206 | WORKDIR /notebooks 207 | COPY ./notebk.sh ./ 208 | 209 | WORKDIR /root 210 | RUN chmod 755 . 211 | COPY ./startup.sh startup.sh 212 | COPY ./jup-config.py jup-config.py 213 | 214 | # For authentication if we aren't using OAuth 215 | RUN git clone -b v1.2 --depth 1 https://github.com/stevenrbrandt/cyolauthenticator.git 216 | RUN pip3 install git+https://github.com/stevenrbrandt/cyolauthenticator.git 217 | 218 | # Use this CMD for a jupyterhub 219 | # CMD bash startup.sh 220 | 221 | COPY clingk.py /usr/install/cling/src/tools/cling/tools/Jupyter/kernel/clingkernel.py 222 | # RUN ln -s /usr/${CLING}/lib/libclingJupyter.so /usr/lib/libclingJupyter.so 223 | # RUN ln -s /usr/${CLING}/lib/clang /usr/lib/clang 224 | # RUN ln -s /usr/${CLING}/include/cling /usr/include/cling 225 | RUN echo "export PYTHONPATH=${PYTHONPATH}" >> /etc/bashrc 226 | #RUN dnf install -y ImageMagick file hostname 227 | COPY is_expr.py /usr/local/python 228 | COPY logo.png /usr/local/share/jupyterhub/static/images/ 229 | COPY teleplot.hpp /usr/include 230 | 231 | COPY ./Dockerfile /Dockerfile 232 | USER jovyan 233 | 234 | RUN mkdir -p /home/jovyan/bot 235 | COPY bot/cxxbot.py /home/jovyan/bot/ 236 | COPY bot/teleplot.py /home/jovyan/bot/ 237 | COPY bot/telecling.py /home/jovyan/bot/ 238 | COPY bot/thumbsup.png /home/jovyan/bot/ 239 | COPY bot/colored.py /home/jovyan/bot/ 240 | RUN pip3 install --user randpass python-telegram-bot 241 | 242 | WORKDIR /home/jovyan 243 | COPY nb.py /root/ 244 | COPY vector_pack_type.hpp /usr/local/include/hpx/execution/traits/detail/simd/vector_pack_type.hpp 245 | CMD bash /notebooks/notebk.sh 246 | -------------------------------------------------------------------------------- /Dockerfile.ubuntu: -------------------------------------------------------------------------------- 1 | # FROM fedora:33 2 | #RUN dnf install -y gcc-c++ gcc make git \ 3 | # bzip2 hwloc-devel blas blas-devel lapack lapack-devel boost-devel \ 4 | # libatomic which vim-enhanced wget zlib-devel cmake \ 5 | # python3-flake8 gdb sudo python3 python3-pip openmpi-devel sqlite-devel sqlite \ 6 | # findutils openssl-devel papi papi-devel lm_sensors-devel tbb-devel \ 7 | # xz bzip2 patch flex openssh-server \ 8 | # texlive-xetex texlive-bibtex texlive-adjustbox texlive-caption texlive-collectbox \ 9 | # texlive-enumitem texlive-environ texlive-eurosym texlive-jknapltx texlive-parskip \ 10 | # texlive-pgf texlive-rsfs texlive-tcolorbox texlive-titling texlive-trimspaces \ 11 | # texlive-ucs texlive-ulem texlive-upquote texlive-latex pandoc 12 | FROM ubuntu:22.04 13 | ENV DEBIAN_FRONTEND noninteractive 14 | RUN apt update -y && apt install -y bzip2 libhwloc-dev vim git gdb python3 python3-pip \ 15 | libpapi-dev patch cmake libblas-dev liblapack-dev libtbb-dev patch npm \ 16 | libglew-dev libboost-all-dev \ 17 | t1-xfree86-nonfree ttf-xfree86-nonfree ttf-xfree86-nonfree-syriac xfonts-75dpi xfonts-100dpi \ 18 | dpkg-dev cmake g++ gcc binutils libx11-dev libxpm-dev libxft-dev libxext-dev imagemagick \ 19 | && apt clean 20 | 21 | ARG CPUS 22 | ARG BUILD_TYPE 23 | 24 | WORKDIR / 25 | ## ENV GCC_VER 8.4.0 26 | ## COPY install-from-spack.sh /usr/local/bin 27 | ## RUN bash /usr/local/bin/install-from-spack.sh 28 | ## COPY alternatives.sh /usr/local/bin 29 | ## RUN bash /usr/local/bin/alternatives.sh 30 | 31 | # ENV AH_VER 4.6.0 32 | # RUN curl -kLO https://www.dyninst.org/sites/default/files/downloads/harmony/ah-${AH_VER}.tar.gz 33 | # RUN tar -xzf ah-${AH_VER}.tar.gz 34 | # WORKDIR /activeharmony-${AH_VER} 35 | # COPY ./activeharmony-4.6.0/code-server/code_generator.cxx code-server/code_generator.cxx 36 | # RUN make CFLAGS=-fPIC LDFLAGS=-fPIC && make install prefix=/usr/local/activeharmony 37 | 38 | # ENV OTF2_VER 2.1.1 39 | # WORKDIR / 40 | # RUN curl -kLO https://www.vi-hps.org/cms/upload/packages/otf2/otf2-${OTF2_VER}.tar.gz 41 | # RUN tar -xzf otf2-${OTF2_VER}.tar.gz 42 | # WORKDIR otf2-${OTF2_VER} 43 | # RUN ./configure --prefix=/usr/local/otf2 --enable-shared && make && make install 44 | 45 | #RUN ln -s /usr/lib64/openmpi/lib/libmpi_cxx.so /usr/lib64/openmpi/lib/libmpi_cxx.so.1 46 | #RUN ln -s /usr/lib64/openmpi/lib/libmpi.so /usr/lib64/openmpi/lib/libmpi.so.12 47 | 48 | #ENV PYVER 3.6.8 49 | #WORKDIR / 50 | #RUN wget https://www.python.org/ftp/python/${PYVER}/Python-${PYVER}.tgz 51 | #RUN tar xf Python-${PYVER}.tgz 52 | #WORKDIR /Python-${PYVER} 53 | #RUN ./configure 54 | #RUN make -j ${CPUS} install 55 | 56 | ## Make headers available 57 | #RUN cp /Python-${PYVER}/pyconfig.h /Python-${PYVER}/Include 58 | #RUN ln -s /Python-${PYVER}/Include /usr/include/python${PYVER} 59 | 60 | #RUN pip3 install --trusted-host pypi.org --trusted-host files.pythonhosted.org numpy tensorflow keras CNTK pytest 61 | #RUN pip3 install numpy tensorflow keras CNTK pytest 62 | WORKDIR / 63 | 64 | #RUN dnf install -y python3-devel 65 | 66 | WORKDIR / 67 | RUN git clone --depth 1 https://github.com/pybind/pybind11.git && \ 68 | mkdir -p /pybind11/build && \ 69 | cd /pybind11/build && \ 70 | cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DPYBIND11_PYTHON_VERSION=${PYVER} .. && \ 71 | make -j ${CPUS} install && \ 72 | rm -f $(find . -name \*.o) 73 | 74 | RUN git clone --depth 1 https://bitbucket.org/blaze-lib/blaze.git && \ 75 | cd /blaze && \ 76 | mkdir -p /blaze/build && \ 77 | cd /blaze/build && \ 78 | cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .. && \ 79 | make -j ${CPUS} install && \ 80 | rm -f $(find . -name \*.o) 81 | 82 | RUN git clone --depth 1 https://github.com/STEllAR-GROUP/blaze_tensor.git && \ 83 | mkdir -p /blaze_tensor/build && \ 84 | cd /blaze_tensor/build && \ 85 | cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} .. && \ 86 | make -j ${CPUS} install && \ 87 | rm -f $(find . -name \*.o) 88 | 89 | WORKDIR /etc/skel 90 | #COPY ./notebooks/*.ipynb ./ 91 | #RUN git clone --depth 1 https://github.com/shortcourse/USACM16-shortcourse 92 | RUN git clone --depth 1 https://github.com/shortcourse/WCCM-APCOM-22 93 | RUN find . | xargs -d '\n' chmod +r 94 | 95 | #RUN dnf install -y nodejs psmisc tbb-devel 96 | RUN pip3 install --upgrade pip 97 | RUN pip3 install jupyter jupyterhub matplotlib numpy termcolor 98 | 99 | ENV DATE 2020-03-10 100 | RUN mkdir -p /usr/install/cling 101 | WORKDIR /usr/install/cling 102 | RUN git clone --branch cling-patches http://root.cern.ch/git/llvm.git src 103 | WORKDIR /usr/install/cling/src 104 | RUN git checkout ac712f0f44b45a1455a302dd6cbb7b6cce269d2d 105 | WORKDIR /usr/install/cling/src/tools 106 | RUN git clone http://root.cern.ch/git/cling.git 107 | WORKDIR /usr/install/cling/src/tools/cling 108 | RUN git checkout 2949bf96b71f9301247275a8097a060aae3429f4 109 | WORKDIR /usr/install/cling/src/tools 110 | RUN git clone --branch cling-patches http://root.cern.ch/git/clang.git 111 | WORKDIR /usr/install/cling/src/tools/clang 112 | RUN git checkout 25f804797f80b69d8c56794e3e0300acd9458958 113 | 114 | WORKDIR /usr/install/cling/src/tools/cling 115 | 116 | RUN mkdir -p /usr/install/cling/src/build 117 | COPY Pipe.hpp /usr/local/include/ 118 | COPY Augment_Kernel.hpp /usr/local/include 119 | COPY Kernel.cpp /usr/install/cling/src/tools/cling/tools/Jupyter 120 | 121 | WORKDIR /usr/install/cling/src/build 122 | RUN cmake -DCMAKE_INSTALL_PREFIX=/usr \ 123 | -DCMAKE_BUILD_TYPE=Release \ 124 | -DCMAKE_CXX_FLAGS='-Wl,-s' \ 125 | -DLLVM_ENABLE_RTTI=ON \ 126 | -DLLVM_ENABLE_EH=ON \ 127 | /usr/install/cling/src 128 | # RUN dnf install -y patch 129 | WORKDIR /usr/install/cling/src 130 | COPY limits.patch . 131 | RUN patch -p1 < limits.patch 132 | WORKDIR /usr/install/cling/src/tools/cling 133 | COPY noexcept.patch ./ 134 | RUN patch -p1 < noexcept.patch 135 | WORKDIR /usr/install/cling/src/build 136 | COPY make.sh /usr/install/cling/src/build/ 137 | RUN bash ./make.sh 138 | RUN cd /usr/install/cling/src/tools/cling/tools/Jupyter/kernel && \ 139 | pip3 install -e . && \ 140 | jupyter-kernelspec install cling-cpp17 && \ 141 | npm install -g configurable-http-proxy 142 | WORKDIR /usr 143 | ## ENV CLING cling_2020-11-05_ROOT-fedora32 144 | ## ENV CLING_TARBALL ${CLING}.tar.bz2 145 | ## RUN curl -LO https://root.cern/download/cling/${CLING_TARBALL} && \ 146 | ## tar xjf ${CLING_TARBALL} && \ 147 | ## rm -f ${CLING_TARBALL} 148 | ## WORKDIR /usr/${CLING}/share/cling/Jupyter/kernel 149 | ## RUN pip3 install -e . && \ 150 | ## jupyter-kernelspec install cling-cpp17 && \ 151 | ## npm install -g configurable-http-proxy && \ 152 | ## ln -s /usr/${CLING}/bin/cling /usr/bin/cling 153 | 154 | RUN git clone -b 1.8.1 --depth 1 https://github.com/STEllAR-GROUP/hpx.git /hpx 155 | WORKDIR /hpx 156 | RUN mkdir -p /hpx/build 157 | WORKDIR /hpx/build 158 | #RUN env CXX=$(which clang++) cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 159 | RUN cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 160 | -DHPX_FILESYSTEM_WITH_BOOST_FILESYSTEM_COMPATIBILITY=ON \ 161 | -DHPX_WITH_CXX17_HARDWARE_DESTRUCTIVE_INTERFERENCE_SIZE=OFF \ 162 | -DHPX_WITH_FETCH_ASIO=ON \ 163 | -DHPX_WITH_BUILTIN_INTEGER_PACK=OFF \ 164 | -DHPX_WITH_ITTNOTIFY=OFF \ 165 | -DHPX_WITH_THREAD_COMPATIBILITY=ON \ 166 | -DHPX_WITH_MALLOC=system \ 167 | -DHPX_WITH_MORE_THAN_64_THREADS=ON \ 168 | -DHPX_WITH_MAX_CPU_COUNT=80 \ 169 | -DHPX_WITH_EXAMPLES=Off \ 170 | -DHPX_WITH_CXX_STANDARD=17 \ 171 | -DCMAKE_BUILD_TYPE=RelWithDebugInfo \ 172 | .. && \ 173 | make -j ${CPUS} install && \ 174 | rm -f $(find . -name \*.o) 175 | RUN mkdir -p /hpx/build2 176 | WORKDIR /hpx/build2 177 | #RUN env CXX=$(which clang++) cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 178 | RUN cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ 179 | -DHPX_FILESYSTEM_WITH_BOOST_FILESYSTEM_COMPATIBILITY=ON \ 180 | -DHPX_WITH_CXX17_HARDWARE_DESTRUCTIVE_INTERFERENCE_SIZE=OFF \ 181 | -DHPX_WITH_FETCH_ASIO=ON \ 182 | -DHPX_WITH_BUILTIN_INTEGER_PACK=OFF \ 183 | -DHPX_WITH_ITTNOTIFY=OFF \ 184 | -DHPX_WITH_THREAD_COMPATIBILITY=ON \ 185 | -DHPX_WITH_MALLOC=system \ 186 | -DHPX_WITH_MORE_THAN_64_THREADS=ON \ 187 | -DHPX_WITH_MAX_CPU_COUNT=80 \ 188 | -DHPX_WITH_EXAMPLES=Off \ 189 | -DHPX_WITH_CXX_STANDARD=20 \ 190 | -DHPX_WITH_DATAPAR_BACKEND=STD_EXPERIMENTAL_SIMD \ 191 | -DCMAKE_BUILD_TYPE=RelWithDebugInfo \ 192 | -DCMAKE_INSTALL_PREFIX=/usr/local/hpx-corot \ 193 | .. && \ 194 | make -j ${CPUS} install && \ 195 | rm -f $(find . -name \*.o) 196 | 197 | ## RUN (make -j 8 install 2>&1 | tee make.out) 198 | COPY ./run_hpx.cpp /usr/include/run_hpx.cpp 199 | RUN chmod 644 /usr/include/run_hpx.cpp 200 | 201 | RUN pip3 install oauthenticator 202 | #RUN dnf install -y procps cppcheck python3-pycurl sqlite python3-libs 203 | COPY ./login.html /usr/local/share/jupyterhub/templates/login.html 204 | COPY ./login2.html /root 205 | COPY ./stellar-logo.png /usr/local/share/jupyterhub/static/images/ 206 | 207 | ENV PYTHONPATH /usr/local/python 208 | RUN mkdir -p /usr/local/python 209 | COPY ./mkuser.py ${PYTHONPATH}/mkuser.py 210 | COPY ./mkuser.py /usr/local/bin/mkuser 211 | RUN chmod 755 /usr/local/bin/mkuser 212 | RUN pip3 install tornado #==5.1.1 # There's a bug in newer versions 213 | COPY ./clingk.py /usr/${CLING}/share/cling/Jupyter/kernel/clingkernel.py 214 | RUN python3 -c 'import sys; print(sys.path[-1])' > /tmp/path.txt 215 | COPY ./find.py ${PYTHONPATH}/ 216 | COPY ./pipes1.py ${PYTHONPATH}/ 217 | COPY ./pipes3.py ${PYTHONPATH}/ 218 | COPY ./cling.py ${PYTHONPATH}/ 219 | COPY ./py11.py ${PYTHONPATH}/ 220 | RUN python3 ${PYTHONPATH}/find.py > /usr/hpx-libs.txt 221 | #RUN cp /Python-${PYVER}/pyconfig.h /Python-${PYVER}/Include 222 | #RUN ln -s /Python-${PYVER}/Include /usr/include/python${PYVER} 223 | WORKDIR / 224 | 225 | RUN git clone --depth 1 https://github.com/STEllAR-GROUP/BlazeIterative 226 | WORKDIR /BlazeIterative/build 227 | RUN cmake .. 228 | RUN make install 229 | 230 | # For some reason, HPX will not link in @py11() unless I do this 231 | RUN ldconfig /usr/local/lib64 232 | 233 | WORKDIR /notebooks 234 | COPY ./notebk.sh ./ 235 | 236 | WORKDIR /root 237 | RUN chmod 755 . 238 | COPY ./startup.sh startup.sh 239 | COPY ./jup-config.py jup-config.py 240 | 241 | # For authentication if we aren't using OAuth 242 | RUN git clone -b v1.2 --depth 1 https://github.com/stevenrbrandt/cyolauthenticator.git 243 | RUN pip3 install git+https://github.com/stevenrbrandt/cyolauthenticator.git@v1.2 244 | 245 | # Use this CMD for a jupyterhub 246 | # CMD bash startup.sh 247 | 248 | COPY clingk.py /usr/install/cling/src/tools/cling/tools/Jupyter/kernel/clingkernel.py 249 | # RUN ln -s /usr/${CLING}/lib/libclingJupyter.so /usr/lib/libclingJupyter.so 250 | # RUN ln -s /usr/${CLING}/lib/clang /usr/lib/clang 251 | # RUN ln -s /usr/${CLING}/include/cling /usr/include/cling 252 | RUN echo "export PYTHONPATH=${PYTHONPATH}" >> /etc/bashrc 253 | #RUN dnf install -y ImageMagick file hostname 254 | COPY is_expr.py /usr/local/python 255 | COPY cin.py /usr/local/python 256 | COPY logo.png /usr/local/share/jupyterhub/static/images/ 257 | COPY teleplot.hpp /usr/include 258 | 259 | COPY ./Dockerfile /Dockerfile 260 | # Not sure why this makes sense 261 | RUN ln -s /usr/lib/x86_64-linux-gnu/libboost_system.so.1.74.0 /usr/lib64/libboost_system.so.1.0.0 262 | RUN python3 -m pip install piraha==1.1.7 263 | 264 | COPY ./notebooks/*.ipynb /etc/skel/ 265 | RUN useradd -m jovyan -s /bin/bash 266 | USER jovyan 267 | WORKDIR /home/jovyan 268 | ENV LD_LIBRARY_PATH /home/jovyan/install/phylanx/lib64:/usr/local/lib64:/home/jovyan/install/phylanx/lib/phylanx:/usr/lib64/openmpi/lib 269 | 270 | RUN mkdir -p /home/jovyan/bot 271 | COPY bot/cxxbot.py /home/jovyan/bot/ 272 | COPY bot/teleplot.py /home/jovyan/bot/ 273 | COPY bot/telecling.py /home/jovyan/bot/ 274 | COPY bot/thumbsup.png /home/jovyan/bot/ 275 | COPY bot/colored.py /home/jovyan/bot/ 276 | RUN pip3 install --user randpass python-telegram-bot 277 | 278 | WORKDIR /home/jovyan 279 | COPY nb.py /root/ 280 | COPY hpxcxx /usr/local/bin/ 281 | COPY vector_pack_type.hpp /usr/local/include/hpx/execution/traits/detail/simd/vector_pack_type.hpp 282 | CMD bash /notebooks/notebk.sh 283 | -------------------------------------------------------------------------------- /cin.py: -------------------------------------------------------------------------------- 1 | # A simple calculator based on Piraha 2 | 3 | import sys 4 | from piraha import Grammar, compileSrc, Matcher 5 | from io import StringIO 6 | 7 | src_code = r""" 8 | skipper=([ \t\r\n]|//.*)* 9 | directive= \#.* 10 | name=[a-zA-Z_][a-zA-Z_0-9]* 11 | type=(const |){name}(::{name})*(< {astuff}+ >|)( [*&])* 12 | quote="(\\.|[^"])*" 13 | char='(\\.|[^'])' 14 | 15 | angle=< {astuff} > 16 | paren=\({sstuff}*\) 17 | brak=\[{stuff}*\] 18 | curl=\{{sstuff}*\} 19 | sstuff=([^{}()\[\]"]+|{paren}|{brak}|{quote}|{curl}|{char}) 20 | stuff=([^{}()\[\]";]+|{paren}|{brak}|{quote}|{curl}|{char}) 21 | astuff=([^{}()\[\]";<>]+|{paren}|{brak}|{quote}|{curl}|{char}|< {astuff}+ >) 22 | 23 | tfunc=template {angle} {func} 24 | tclass=template {angle} {class} 25 | func=(static|) (inline|) {type} {name} {paren} {curl} 26 | class=(struct|class) {name} (: {type}( , {type})* |){curl} ; 27 | declargs=({paren}|{curl}|) 28 | 29 | rhs = {stuff}+ 30 | array_decl={type} {name} \[ {stuff} \]( = {curl}|) ; 31 | decl={type} {name} {declargs} ; 32 | ns = namespace {name}( :: {name})*( = {name}( :: {name})* ;| {curl}) 33 | lambda_rhs={brak} {paren} (-> {type} |){curl} 34 | lambda_assign={type} {name} = {lambda_rhs} ; 35 | curl_assign={type} {name} = {curl} ; 36 | assign={type} {name} = {rhs} ; 37 | for=for {paren} {stmt} 38 | if=if {paren} {stmt}( {else_if}|)*( {else}) 39 | else=else {stmt} 40 | else_if=else if {paren} {stmt} 41 | while=while \({stuff}\) {stmt} 42 | expr={stuff}+ ; 43 | call={name}( :: {name})* {paren} ; 44 | del=delete {stuff} ; 45 | stmt=({for}|{if}|{while}|{ns}|{del}|{array_decl}|{decl}|{lambda_assign}|{curl_assign}|{assign}|{curl}|{macro}|{call}|{curl}|{expr}) 46 | macro=[A-Z][_A-Z]+ {paren}( ;|) 47 | using=using {rhs} ; 48 | typedef=typedef {rhs} ; 49 | namespace=namespace {curl} 50 | 51 | src=^( ({quote}|{namespace}|{using}|{typedef}|{directive}|{ns}|{tfunc}|{tclass}|{class}|{func}|{stmt}))* $ 52 | """ 53 | 54 | g = Grammar() 55 | 56 | # Compile a grammar from a file 57 | compileSrc(g, src_code) 58 | 59 | # Create a matcher 60 | def parse_cxx(cinput): 61 | m = Matcher(g,g.default_rule, cinput) 62 | if m.matches(): 63 | pass 64 | #print("Success! Dump parse tree...") 65 | #with open("cin-debug.txt", "w") as fd: 66 | # print(m.gr.dump(),file=fd) 67 | outs = "" 68 | for k in m.gr.children: 69 | pnm = k.getPatternName() 70 | if pnm == "stmt": 71 | for k2 in k.children: 72 | pnm2 = k2.getPatternName() 73 | outs += pnm2 + "\n" 74 | else: 75 | outs += pnm + "\n" 76 | return m.gr, outs 77 | else: 78 | # Show a helpful error message 79 | #print(cinput) 80 | s = StringIO() 81 | m.showError(s) 82 | s.seek(0) 83 | erm = s.read() 84 | return None, erm 85 | 86 | code_wrap = """ 87 | struct foo__%d_ { 88 | foo__%d_() { 89 | run_hpx([](){ 90 | %s 91 | }); 92 | } 93 | } foo_inst_%d_; 94 | """ 95 | 96 | use_hpx = False 97 | #code_num = 0 98 | 99 | class CodeGen: 100 | def __init__(self): 101 | self.wrapping_vars = list() 102 | self.code_num = 0 103 | 104 | def add(self, pn, g): 105 | if pn in ["lambda_assign", "curl_assign", "assign"]: 106 | vtype = g.children[0].substring() 107 | vname = g.children[1].substring() 108 | rhs = g.children[2].substring() 109 | if "future" in vtype or ".get()" in rhs or ".then(" in rhs or "hpx" in rhs: 110 | return f"{vtype} {vname} = run_hpx([](){{ return {rhs}; }});\n" 111 | else: 112 | return g.substring()+"\n" 113 | elif pn == "decl": 114 | vtype = g.children[0].substring() 115 | vname = g.children[1].substring() 116 | vargs = g.children[2].substring() 117 | if "future" in vtype or ".get()" in vargs or ".then(" in vargs or "hpx" in vargs: 118 | return f"{vtype} {vname} = run_hpx([](){{ return {vtype}({vargs}); }});" 119 | else: 120 | return g.substring() 121 | elif pn in ["expr", "call", "for", "if", "curl", "del"]: 122 | code_num = self.code_num 123 | self.code_num += 1 124 | code_num = self.code_num 125 | self.wrapping_vars += [None] 126 | if use_hpx: 127 | return f"struct wrapping_{code_num}__ {{ wrapping_{code_num}__() {{ run_hpx([]() {{ {g.substring()} }}); }} }} wrapping_{code_num}__var__ ;\n" 128 | else: 129 | return f"struct wrapping_{code_num}__ {{ wrapping_{code_num}__() {{ {g.substring()} }} }} wrapping_{code_num}__var__ ;\n" 130 | else: 131 | return g.substring()+self.flush() 132 | 133 | def flush(self): 134 | return "\n" 135 | code = "" 136 | if len(self.wrapping_vars) > 0: 137 | code_num = self.code_num 138 | code += f"wrapping_{code_num}__ *inner_{code_num}__ = " 139 | if use_hpx: 140 | code += "run_hpx([](){ " 141 | code += f" return new wrapping_{code_num}__(); " 142 | code += "});\n" 143 | else: 144 | code += f" new wrapping_{code_num}__(); " 145 | for vv in self.wrapping_vars: 146 | if vv is None: 147 | continue 148 | else: 149 | code += f"{vv[0]} {vv[1]} = std::move(inner_{code_num}__->{vv[1]});\n" 150 | #code += f"delete inner_{code_num}__;\n" 151 | self.wrapping_vars = list() 152 | return code 153 | 154 | cgen = CodeGen() 155 | 156 | prior_defs = dict() 157 | 158 | def redef(symbol): 159 | val = prior_defs.get(symbol, None) 160 | if val is None: 161 | prior_defs[symbol] = 1 162 | return "" 163 | elif val == 1: 164 | prior_defs[symbol] += 1 165 | return f"#define {symbol} {symbol}_redef__{val}\n" 166 | else: 167 | prior_defs[symbol] += 1 168 | return f"#undef {symbol}\n#define {symbol} {symbol}_redef__{val}\n" 169 | 170 | def hpxify(cinput): 171 | global use_hpx, code_num 172 | 173 | # Backwards compatible with older versions of the C++Explorer 174 | if cinput.startswith(".expr"): 175 | cinput = "{" + cinput[5:] + "}" 176 | 177 | m, outs = parse_cxx(cinput) 178 | #print("Parse Tree:",m.dump()) 179 | if m is None: 180 | return cinput, use_hpx, False, outs 181 | code = "" 182 | inc_run_hpx = False 183 | has_main = False 184 | for g in m.children: 185 | pn = g.getPatternName() 186 | if pn in ["func", "tfunc"]: 187 | func_name = g.children[1].substring() 188 | code += redef(func_name) 189 | if pn == "func" and func_name == "main": 190 | has_main = True 191 | elif pn in ["class", "tclass"]: 192 | class_name = g.children[0].substring() 193 | code += redef(class_name) 194 | elif pn == "stmt": # and use_hpx: 195 | for g2 in g.children: 196 | pn2 = g2.getPatternName() 197 | if pn2 in ["lambda_assign", "curl_assign", "assign", "decl", "array_decl"]: 198 | var_name = g2.children[1].substring() 199 | code += redef(var_name) 200 | 201 | for g in m.children: 202 | pn = g.getPatternName() 203 | txt = g.substring() 204 | if pn in ["directive"]: 205 | code += g.substring()+"\n" 206 | if (not use_hpx) and "hpx" in g.substring(): 207 | use_hpx = True 208 | if (not inc_run_hpx) and "hpx" in g.substring(): 209 | inc_run_hpx = True 210 | code += "#include \n" 211 | elif pn == "stmt": # and use_hpx: 212 | for g2 in g.children: 213 | pn2 = g2.getPatternName() 214 | if pn2 in ["lambda_assign", "curl_assign", "assign", "decl"]: 215 | if "auto" in g2.children[0].substring(): 216 | code += cgen.flush() 217 | if pn2 == "assign": 218 | code += g2.children[0].substring()+" " 219 | code += g2.children[1].substring()+" = " 220 | if use_hpx: 221 | code += "run_hpx([](){ return " + g2.children[2].substring() + ";});\n" 222 | else: 223 | code += g2.children[2].substring() + ";\n" 224 | else: 225 | code += g2.substring()+"\n" 226 | else: 227 | code += cgen.add(pn2, g2) 228 | #vtype = g2.children[0].substring() 229 | #vname = g2.children[1].substring() 230 | #if len(wrapping_vars) == 0: 231 | # subclass = "" 232 | #else: 233 | # subclass = f": public wrapping_{code_num}__" 234 | #code_num += 1 235 | #wrapping_vars += [(vtype, vname)] 236 | #code += f"struct wrapping_{code_num}__ {subclass} {{ {g2.substring()}; }};\n" 237 | #wrapping_vars g 238 | elif pn2 in ["expr", "call", "for", "if", "curl", "del"]: 239 | code += cgen.add(pn2, g2) 240 | #if len(wrapping_vars) == 0: 241 | # subclass = "" 242 | #else: 243 | # subclass = f": public wrapping_{code_num}__" 244 | #code_num += 1 245 | #wrapping_vars += [None] 246 | #code += f"struct wrapping_{code_num}__ {subclass} {{ wrapping_{code_num}__() {{ {g2.substring()}; }} }};\n" 247 | #code += code_wrap % (code_num, code_num, txt, code_num) 248 | else: 249 | #if len(wrapping_vars) > 0: 250 | # code += "run([](){\n" 251 | # code += f" wrapping_{code_num}__ *inner_{code_num}__ = new wrapping_{code_num}__();\n" 252 | # code += "});\n" 253 | # for vv in wrapping_vars: 254 | # if vv is None: 255 | # continue 256 | # else: 257 | # code += f"{vv[0]} {vv[1]} = std::move(inner_{code_num}__->vv[1]);\n" 258 | # code += f"delete inner_{code_num}__;\n" 259 | # wrapping_vars = list() 260 | code += cgen.flush() 261 | code += g2.substring()+"\n" 262 | elif pn == "directive": 263 | code += cgen.flush() 264 | code += txt + "\n" 265 | if "hpx/" in txt and not use_hpx and not has_main: 266 | use_hpx = True 267 | code += "#include \n" 268 | else: 269 | code += cgen.flush() 270 | code += txt + "\n" 271 | code += cgen.flush() 272 | #print(">>>",code) 273 | if use_hpx: 274 | pass #code += "hpx_global::shutdown();\n"; 275 | return code, use_hpx, has_main, outs 276 | 277 | if __name__ == "__main__": 278 | if len(sys.argv) > 2: 279 | with open(sys.argv[1], "r") as fd: 280 | cinput = fd.read() 281 | crule = sys.argv[2] 282 | print(crule, cinput) 283 | m = Matcher(g, crule, cinput) 284 | if m.matches(): 285 | print("Success! Dump parse tree...") 286 | print(m.gr.dump()) 287 | else: 288 | m.showError() 289 | else: 290 | cinput = r""" 291 | #include 292 | #include 293 | 294 | using namespace std; 295 | 296 | hpx::future f = hpx::async([](){ return 42; }); 297 | 298 | cout << f.get() << endl; 299 | 300 | executor_type exec(host_targets); 301 | std::vector vd; 302 | for(int i=0;i<10;i++) vd.push_back(1.f); 303 | hpx::fill(execution::par.on(exec),vd.begin(),vd.end(),1.0f*getpid()); 304 | for(int i=0;i<10;i++) cout << vd[i] << " "; cout << std::endl; 305 | """ 306 | crule = "src" 307 | m = Matcher(g, crule, cinput) 308 | if m.matches(): 309 | print("Success!") 310 | src, a, b, outs = hpxify(cinput) 311 | print(src) 312 | print("outs<<",outs,">>") 313 | src, a, b, outs = hpxify(""" 314 | struct A { int a; }; 315 | """) 316 | print(src) 317 | print("outs<<",outs,">>") 318 | src, a, b, outs = hpxify(""" 319 | struct A { int b; }; 320 | """) 321 | print(src) 322 | print("outs<<",outs,">>") 323 | else: 324 | m.showError() 325 | -------------------------------------------------------------------------------- /py11.py: -------------------------------------------------------------------------------- 1 | import os 2 | from subprocess import Popen, PIPE 3 | import re 4 | import sys 5 | import inspect 6 | import ast 7 | import numpy as np 8 | import importlib 9 | from termcolor import colored 10 | 11 | load_func = """ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | static inline void *load_func(const char *fun) { 20 | std::ostringstream fname; 21 | fname << getenv("HOME") << "/tmp/" << fun << ".so.txt"; 22 | std::string so_txt = fname.str(); 23 | 24 | std::ifstream in; 25 | in.open(so_txt.c_str()); 26 | assert(in.good()); 27 | 28 | std::string ver; 29 | in >> ver; 30 | 31 | std::ostringstream fun2; 32 | fun2 << fun << "_v" << ver; 33 | 34 | std::ostringstream lib; 35 | lib << getenv("HOME") << "/tmp/" << fun2.str() << ".so"; 36 | in.close(); 37 | in.open(lib.str().c_str()); 38 | assert(in.good()); 39 | in.close(); 40 | 41 | void *handle = dlopen(lib.str().c_str(), RTLD_LAZY); 42 | return dlsym(handle, fun); 43 | } 44 | """ 45 | 46 | if type(sys.stdout).__module__ == 'ipykernel.iostream' and type(sys.stdout).__name__ == 'OutStream': 47 | is_jupyter = True 48 | else: 49 | is_jupyter = False 50 | 51 | home = os.environ["HOME"] 52 | def tmp_dir(): 53 | return os.path.join(home, "tmp") 54 | 55 | # Figure out where stuff is 56 | info = sys.version_info 57 | vpattern = '^python%d\.%d' % (info.major, info.minor) 58 | for item in os.listdir("/usr/include"): 59 | if re.match(vpattern, item): 60 | python_header = os.path.join("/usr/include",item) 61 | test_file = os.path.join(python_header,"Python.h") 62 | if os.path.exists(test_file): 63 | break 64 | 65 | os.makedirs(tmp_dir(), exist_ok=True) 66 | 67 | # Locate pybind11 68 | if os.path.exists("/usr/local/include/pybind11/pybind11.h"): 69 | pybind11_header = "/usr/local/include" 70 | else: 71 | local = os.path.join(home,".local","include") 72 | if os.path.exists(local): 73 | for item in os.listdir(local): 74 | if re.match(vpattern, item): 75 | pybind11_header = os.path.join(local,item) 76 | test_file = os.path.join(pybind11_header,"pybind11","pybind11.h") 77 | if os.path.exists(test_file): 78 | break 79 | else: 80 | pybind11_header = "[pybind11 install directory]" 81 | 82 | flags = "-std=c++17" 83 | 84 | def set_flags(f): 85 | global flags 86 | flags = f 87 | 88 | def ttran_(n): 89 | "A helper for ttran in translating Python names to C++ names" 90 | if n == "np.float32": 91 | return "std::float32_t"; 92 | elif n == "np.float64": 93 | return "std::float64_t"; 94 | elif n == "np.int64": 95 | return "std::int64_t"; 96 | elif n == "str": 97 | return "std::string" 98 | elif n == "None": 99 | return "void"; 100 | elif n == "List": 101 | return "std::vector" 102 | elif n == "Dict": 103 | return "std::map" 104 | elif n == '[': 105 | return '<' 106 | elif n == ']': 107 | return '>' 108 | else: 109 | return n 110 | 111 | def ttran(n): 112 | "Translate Python names to C++ names" 113 | s = '' 114 | for i in re.finditer(r'[\w\.]+|.',n): 115 | s += ttran_(i.group(0)) 116 | return s 117 | 118 | 119 | class basic_type: 120 | def __init__(self,name=None): 121 | if name is not None: 122 | self.full_name = name 123 | 124 | class template_type: 125 | def __init__(self,name=None): 126 | if name is not None: 127 | self.full_name = name 128 | def __getitem__(self,a): 129 | pass 130 | def __getslice__(self,*a): 131 | pass 132 | 133 | type_names = {} 134 | 135 | def create_type(name,alt=None,is_template=False): 136 | global type_names 137 | assert name is not None 138 | if alt is not None: 139 | type_names[name] = alt 140 | else: 141 | type_names[name] = name 142 | stack = inspect.stack() 143 | if 1 < len(stack): 144 | index = 1 145 | else: 146 | index = 0 147 | if is_template: 148 | stack[index].frame.f_globals[name] = template_type(name) 149 | else: 150 | stack[index].frame.f_globals[name] = basic_type(name) 151 | 152 | create_type("svec",alt="std::vector",is_template=True) 153 | create_type("smap",alt="std::map",is_template=True) 154 | 155 | def gettype(ty): 156 | """ 157 | Extract a C++ type from an AST element. 158 | """ 159 | global type_names 160 | if ty is None: 161 | return "None" 162 | t = type(ty) 163 | if t == ast.Name: 164 | if ty.id in type_names.keys(): 165 | return type_names[ty.id] 166 | return ty.id 167 | elif t in [np.float64]: 168 | return str(t) 169 | elif t in [ast.Index, ast.NameConstant]: 170 | return gettype(ty.value) 171 | elif t in [ast.Attribute]: 172 | return gettype(ty.value)+"."+gettype(ty.attr) 173 | elif t == ast.Subscript: 174 | return gettype(ty.value)+'['+gettype(ty.slice)+']' 175 | elif t == ast.Tuple: 176 | # If we're processing a Dict[str,str] 177 | # the "str,str" part is an ast.Tuple 178 | s = '' 179 | sep = '' 180 | for e in ty.elts: 181 | s += sep + gettype(e) 182 | sep = ',' 183 | return s 184 | elif t == ast.Call: 185 | if ty.func.id == "Ref": 186 | return "%s&" % gettype(ty.args[0]) 187 | elif ty.func.id == "Const": 188 | return "%s const" % gettype(ty.args[0]) 189 | elif ty.func.id == "Move": 190 | return "%s&&" % gettype(ty.args[0]) 191 | elif ty.func.id == "Ptr": 192 | return "%s*" % gettype(ty.args[0]) 193 | else: 194 | s = ty.func.id + "<" 195 | for i in len(ty.args): 196 | if i > 0: 197 | s += "," 198 | arg = ty.args[i] 199 | s += gettype(arg) 200 | s += ">" 201 | return s 202 | elif type(ty) == str: 203 | print(ty) 204 | raise Exception("?") 205 | elif type(ty) == ast.Constant: 206 | if ty.value is None: 207 | return "void" 208 | else: 209 | raise Exception() 210 | else: 211 | print(ty.func.id) 212 | print(ty.args,"//",dir(ty.args[0])) 213 | print(ty.args[0].s, ty.args[1].id) 214 | print("<<",ty.__class__.__name__,">>",dir(ty)) 215 | raise Exception("?") 216 | 217 | 218 | def get_args(tree): 219 | nm = tree.__class__.__name__ 220 | 221 | if nm in ["Module"]: 222 | for k in tree.body: 223 | args = get_args(k) 224 | if args is not None: 225 | return args 226 | 227 | elif nm in ["FunctionDef"]: 228 | args = [] 229 | cargs = [] 230 | oargs = "" 231 | for a in tree.args.args: 232 | type = ttran(gettype(a.annotation)) 233 | args += [type+" "+a.arg] 234 | oargs += ',py::arg("%s")' % a.arg 235 | cargs += [a.arg] 236 | #oargs += ','+type 237 | return [",".join(args), oargs, cargs, ttran(gettype(tree.returns)) ] 238 | 239 | raise Exception("Could not find args") 240 | 241 | class fcall: 242 | def __init__(self,base,fun_name,suffix,args,rettype): 243 | self.base = base 244 | self.fun_name = fun_name 245 | assert not re.match(r'.*_v\d+$',fun_name), fun_name 246 | self.suffix = suffix 247 | self.args_decl = args 248 | self.rettype = rettype 249 | if tmp_dir() not in sys.path: 250 | sys.path += [tmp_dir()] 251 | fpath = os.path.join(tmp_dir(),fun_name+suffix+".so") 252 | self.m = importlib.import_module(fun_name+suffix,fpath) 253 | 254 | def __call__(self,*args): 255 | self.m.load() 256 | if is_jupyter: 257 | try: 258 | outfile = os.path.join(tmp_dir(),"out.txt") 259 | fd1 = open(outfile, "w") 260 | save_out = os.dup(1) 261 | os.close(1) 262 | os.dup(fd1.fileno()) 263 | 264 | errfile = os.path.join(tmp_dir(),"err.txt") 265 | fd2 = open(errfile, "w") 266 | save_err = os.dup(2) 267 | os.close(2) 268 | os.dup(fd2.fileno()) 269 | 270 | return self.m.call(*args) 271 | finally: 272 | fd1.close() 273 | os.close(1) 274 | os.dup(save_out) 275 | os.close(save_out) 276 | print(open(outfile,"r").read(),end='') 277 | 278 | fd2.close() 279 | os.close(2) 280 | os.dup(save_err) 281 | os.close(save_err) 282 | print(colored(open(errfile,"r").read(),"red"),end='') 283 | else: 284 | return self.m.call(*args) 285 | 286 | # Create the basic source code 287 | def write_src(**kwargs): 288 | 289 | wrapper = kwargs['wrapper'] 290 | raw_name = kwargs["raw_name"] 291 | args = kwargs["args"] 292 | oargs = kwargs["oargs"] 293 | rettype = kwargs["rettype"] 294 | 295 | if wrapper is not None: 296 | cargs = kwargs["cargs"] 297 | call_args = "(" + ",".join(cargs) + ")" 298 | kwargs['wrap'] = wrap_src( 299 | f=raw_name, 300 | args=args, 301 | rettype=rettype, 302 | oargs=oargs, 303 | call_args=call_args, 304 | wrapper=wrapper.fun_name 305 | ) 306 | kwargs['wrap_name'] = raw_name + "_wrapped" 307 | else: 308 | kwargs['wrap_name'] = raw_name 309 | kwargs['wrap'] = '' 310 | 311 | return """ 312 | #include 313 | #include 314 | {headers} 315 | 316 | {fun_decls} 317 | 318 | namespace py = pybind11; 319 | 320 | extern "C" {rettype} {raw_name}({args}){{ 321 | {body} 322 | }}; 323 | 324 | {wrap} 325 | 326 | extern "C" void load_functions() {{ 327 | {fun_calls} 328 | }} 329 | 330 | PYBIND11_MODULE({name}, m) {{ 331 | m.def("load",load_functions,"function"), 332 | m.def("call",{wrap_name},"function"{oargs}); 333 | }} 334 | """.format(**kwargs) 335 | 336 | def wrap_src(**kwargs): 337 | if kwargs["rettype"] == "void": 338 | src = """ 339 | void {f}_wrapped({args}) {{ 340 | std::function f = [&](){{ 341 | {f}{call_args}; 342 | }}; 343 | {wrapper}(f); 344 | }} 345 | """.format(**kwargs) 346 | else: 347 | src = """ 348 | {rettype} {f}_wrapped({args}) {{ 349 | {rettype} r; 350 | std::function f = [&](){{ 351 | r = {f}{call_args}; 352 | }}; 353 | {wrapper}(f); 354 | return r; 355 | }} 356 | """.format(**kwargs) 357 | return src 358 | 359 | class py11: 360 | 361 | def __init__(self,*kargs,**kwargs): 362 | 363 | if 'recompile' in kwargs: 364 | self.recompile = kwargs['recompile'] 365 | else: 366 | self.recompile = False 367 | 368 | if 'headers' in kwargs: 369 | self.headers = kwargs['headers'] 370 | else: 371 | self.headers = [] 372 | 373 | fun_decls = '' 374 | fun_calls = '' 375 | funs_list = [] 376 | if 'funs' in kwargs: 377 | funs_list += kwargs['funs'] 378 | if 'wrap' in kwargs: 379 | wrapper = kwargs['wrap'] 380 | assert wrapper != None 381 | funs_list += [wrapper] 382 | self.wrapper = wrapper 383 | else: 384 | self.wrapper = None 385 | 386 | if len(funs_list) > 0: 387 | fun_decls += load_func 388 | for f in funs_list: #kwargs['funs']: 389 | f1 = '' 390 | f2 = '' 391 | f1 += 'typedef {rettype}(*{f}_type_def)({args_decl});\n' 392 | f1 += '{f}_type_def {f} = nullptr;\n' 393 | f2 += '{f} = ({f}_type_def)load_func("{f}");\n' 394 | f1 = f1.format( 395 | f=f.fun_name, 396 | dir=tmp_dir(), 397 | rettype=f.rettype, 398 | args_decl=f.args_decl); 399 | f2 = f2.format( 400 | f=f.fun_name, 401 | dir=tmp_dir(), 402 | rettype=f.rettype, 403 | args_decl=f.args_decl); 404 | fun_decls += f1 405 | fun_calls += f2 406 | self.fun_decls = fun_decls 407 | self.fun_calls = fun_calls 408 | 409 | def __call__(self,fun): 410 | base = os.path.join(tmp_dir(), fun.__name__) 411 | src = inspect.getsource(fun) 412 | tree = ast.parse(src) 413 | args, oargs, cargs, rettype = get_args(tree) 414 | code = "" 415 | fname = base+'.cpp' 416 | mname = base+'.so.txt' 417 | 418 | if os.path.exists(mname): 419 | with open(mname, "r") as fd: 420 | version = int(fd.read().strip()) 421 | else: 422 | version = 0 423 | suffix = "_v"+str(version) 424 | libname = base+suffix+'.so' 425 | 426 | # if self.wrapper is not None: 427 | # call_args = "(" + ",".join(cargs) + ")" 428 | # wrap = wrap_src( 429 | # f=fun.__name__, 430 | # args=args, 431 | # rettype=rettype, 432 | # oargs=oargs, 433 | # call_args=call_args, 434 | # wrapper=self.wrapper.fun_name 435 | # ) 436 | # wrap_name = fun.__name__ + "_wrapped" 437 | # else: 438 | # wrap_name = fun.__name__ 439 | # wrap = '' 440 | 441 | src = write_src( 442 | name=fun.__name__+suffix, 443 | raw_name=fun.__name__, 444 | wrapper=self.wrapper, 445 | body=fun.__doc__, 446 | headers='\n'.join(['#include '+h for h in self.headers]), 447 | rettype=rettype, 448 | args=args, 449 | oargs=oargs, 450 | cargs=cargs, 451 | fun_decls=self.fun_decls, 452 | fun_calls=self.fun_calls 453 | ) 454 | 455 | suffix = '' 456 | if os.path.exists(fname): 457 | code = open(fname).read() 458 | suffix = "_v"+str(version) 459 | if code != src or self.recompile or not os.path.exists(libname): 460 | old_file = base + suffix + '.so' 461 | if os.path.exists(old_file): 462 | os.remove(old_file) 463 | version += 1 464 | suffix = "_v"+str(version) 465 | base += suffix 466 | src = write_src( 467 | name=fun.__name__+suffix, 468 | raw_name=fun.__name__, 469 | wrap_name=fun.__name__, 470 | wrapper=self.wrapper, 471 | body=fun.__doc__, 472 | headers='\n'.join(['#include '+h for h in self.headers]), 473 | rettype=rettype, 474 | args=args, 475 | oargs=oargs, 476 | cargs=cargs, 477 | fun_decls=self.fun_decls, 478 | fun_calls=self.fun_calls 479 | ) 480 | 481 | with open(mname, "w") as fd: 482 | print(version,file=fd) 483 | 484 | with open(fname, "w") as fd: 485 | fd.write(src) 486 | cmd="c++ -Wl,--start {flags} -I{python_header} -I{pybind11_header} -rdynamic -fPIC -shared -o {base}.so {fname} -Wl,--end".format(base=base,python_header=python_header,pybind11_header=pybind11_header,flags=flags,fname=fname) 487 | r = 0 488 | try: 489 | print(cmd) 490 | proc = Popen(cmd.split(' '),stdout=PIPE,stderr=PIPE,universal_newlines=True) 491 | outs, errs = proc.communicate() 492 | print(outs,end='') 493 | print(colored(errs,"red"),end='') 494 | r = proc.poll() 495 | except Exception as e: 496 | print(e) 497 | r = 1 498 | print("Except",e) 499 | if r != 0: 500 | if os.path.exists(base+".so"): 501 | os.remove(base+".so") 502 | return None 503 | return fcall(base,fun.__name__,suffix,args,rettype) 504 | -------------------------------------------------------------------------------- /notebooks/HPX_Training.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# HPX + Cling + Jupyter\n", 8 | "\n", 9 | "## Docker Instructions\n", 10 | "* Frist, install docker and docker-compose on your local resource\n", 11 | "* Second, start Docker, e.g. ```sudo service docker start```\n", 12 | "* Third, run `curl -LO https://raw.githubusercontent.com/stevenrbrandt/CxxExplorer/master/docker-compose.yml`\n", 13 | "* Fourth, edit the docker-compose.yml and change the password to something other than `spoon`\n", 14 | "* Fifth, start the notebook by typing `docker-compose up -d`\n", 15 | "* Sixth, play with the existing ipynb files or create new ones.\n", 16 | "* Seven, save your work! This is an important step. If you simply quit the container, everything you did will be lost. You can copy individual files from the image to local disk as follows: `docker cp cxxex-src-nbk:/home/jovyan/HPX_by_example.ipynb ~/`" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "#include " 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "using namespace std;\n", 35 | "using namespace hpx;" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "# What is a (the) Future?\n", 43 | "\n", 44 | "Many ways to get hold of a future, simplest way is to use (std) async:" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "int universal_answer() { return 42; }\n", 54 | "void deep_thought()\n", 55 | "{\n", 56 | " future promised_answer = async(&universal_answer);\n", 57 | " // do other things for 7.5 million years\n", 58 | " cout << promised_answer.get() << endl; // prints 42\n", 59 | "}" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": null, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "deep_thought();" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "# Compositional Facilities" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "future make_string()\n", 85 | "{\n", 86 | " future f1 = async([]()->int { return 123; });\n", 87 | " future f2 = f1.then(\n", 88 | " [](future f) -> string\n", 89 | " {\n", 90 | " return to_string(f.get()); // here .get() won't block\n", 91 | " });\n", 92 | " return f2;\n", 93 | "}" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "cout << make_string().get() << endl;" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "template\n", 112 | "int do_work(W& w) {\n", 113 | " // extract the value of the first argument.\n", 114 | " return hpx::get<0>(w.get()).get();\n", 115 | "}\n", 116 | "\n", 117 | "future test_when_all()\n", 118 | "{\n", 119 | " future future1 = async([]()->int { return 125; });\n", 120 | " future future2 = async([]()->string { return string(\"hi\"); });\n", 121 | " \n", 122 | " auto all_f = when_all(future1,future2);\n", 123 | " \n", 124 | " future result = all_f.then(\n", 125 | " [](auto f)->int {\n", 126 | " return do_work(f);\n", 127 | " });\n", 128 | " return result;\n", 129 | "}" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "cout << test_when_all().get() << endl;" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "# Parallel Algorithms\n", 146 | "HPX allows you to write loop parallel algorithms in a generic fashion, applying to specify the way in which parallelism is achieved (i.e. threads, distributed, cuda, etc.) through polcies." 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": null, 152 | "metadata": {}, 153 | "outputs": [], 154 | "source": [ 155 | "#include \n", 156 | "#include \n", 157 | "#include " 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "vector v{ 1, 2, 3, 4, 5, 6 };" 167 | ] 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": {}, 172 | "source": [ 173 | "## Transform\n", 174 | "Here we demonstrate the transformation of a vector, and the various mechnanisms by which it can performed in parallel." 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "// This parallel tranformation of vector v\n", 184 | "// is done using thread parallelism. An\n", 185 | "// implicit barrier is present at the end.\n", 186 | "hpx::transform (\n", 187 | " hpx::execution::par,\n", 188 | " begin(v), end(v), begin(v),\n", 189 | " [](int i) -> int\n", 190 | " {\n", 191 | " return i+1; \n", 192 | " });\n", 193 | "for(int i : v) cout << i << \",\";" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "// This parallel tranformation of vector v\n", 203 | "// is done using thread parallelism. There\n", 204 | "// is no implicit barrier. Instead, the\n", 205 | "// transform returns a future.\n", 206 | "auto f = hpx::transform (\n", 207 | " execution::par (execution::task),\n", 208 | " begin(v), end(v), begin(v),\n", 209 | " [](int i) -> int\n", 210 | " {\n", 211 | " return i+1; \n", 212 | " });\n", 213 | " // work here...\n", 214 | "// wait for the future to be ready.\n", 215 | "f.wait();\n", 216 | "\n", 217 | "for(int i : v) cout << i << \",\";" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": null, 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [ 226 | "#include \n", 227 | "#include \n", 228 | "#include " 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": null, 234 | "metadata": {}, 235 | "outputs": [], 236 | "source": [ 237 | "// targets are threads. Possibly, they each have their own locality (although by\n", 238 | "// using get_local_targets we'll only get targets on the current locality)\n", 239 | "auto host_targets = hpx::compute::host::get_local_targets();" 240 | ] 241 | }, 242 | { 243 | "cell_type": "code", 244 | "execution_count": null, 245 | "metadata": {}, 246 | "outputs": [], 247 | "source": [ 248 | "// List the locality of all targets. These should all be the same.\n", 249 | "for(auto host : host_targets)\n", 250 | " cout << hpx::get<0>(host.num_pus()) << endl;" 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": null, 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [ 259 | "#include " 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": null, 265 | "metadata": {}, 266 | "outputs": [], 267 | "source": [ 268 | "// Get all targets on all localities and store in host_targets.\n", 269 | "// This notebook only uses a single locality, so this list should\n", 270 | "// be the same as the above.\n", 271 | "host_targets.clear();\n", 272 | "for (hpx::id_type const& locality : hpx::find_all_localities())\n", 273 | "{\n", 274 | " std::vector targets =\n", 275 | " hpx::compute::host::distributed::get_targets(locality).get();\n", 276 | " host_targets.insert(end(host_targets),begin(targets),end(targets));\n", 277 | "}\n", 278 | "for(auto host : host_targets)\n", 279 | " cout << hpx::get<0>(host.num_pus()) << endl;" 280 | ] 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "metadata": {}, 285 | "source": [ 286 | "## Other Algorithms\n", 287 | "There are a great many algorithms. Here we demonstrate a handful of them." 288 | ] 289 | }, 290 | { 291 | "cell_type": "code", 292 | "execution_count": null, 293 | "metadata": {}, 294 | "outputs": [], 295 | "source": [ 296 | "typedef hpx::compute::host::block_executor<> executor_type;" 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": null, 302 | "metadata": {}, 303 | "outputs": [], 304 | "source": [ 305 | "// Do a fill on the listed targets. We have supplied all of them,\n", 306 | "// though we don't need to. Note that the fill algorithm doesn't make sense\n", 307 | "// in a distributed setting since vector vd is not distributed.\n", 308 | "executor_type *exec = new executor_type(host_targets);\n", 309 | "std::vector vd;\n", 310 | "for(int i=0;i<10;i++) vd.push_back(1.f);\n", 311 | "hpx::fill(execution::par.on(*exec),vd.begin(),vd.end(),1.0f*getpid());\n", 312 | "for(int i=0;i<10;i++) cout << vd[i] << \" \"; cout << std::endl;" 313 | ] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "execution_count": null, 318 | "metadata": {}, 319 | "outputs": [], 320 | "source": [ 321 | "#include " 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": null, 327 | "metadata": {}, 328 | "outputs": [], 329 | "source": [ 330 | "for(int i=0;i<10;i++) vd.push_back(1.f*i);\n", 331 | "hpx::reverse(execution::par,vd.begin(),vd.end());\n", 332 | "for(int val : vd) cout << val << \" \";" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": null, 338 | "metadata": {}, 339 | "outputs": [], 340 | "source": [ 341 | "#include " 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": null, 347 | "metadata": {}, 348 | "outputs": [], 349 | "source": [ 350 | "for(int i=0;i<10;i++) vd.push_back(1.f*rand());\n", 351 | "auto ptr = hpx::max_element(execution::par,vd.begin(),vd.end(),std::less());\n", 352 | "for(float val : vd) cout << val << \" \";\n", 353 | "cout << endl << *ptr << endl;" 354 | ] 355 | }, 356 | { 357 | "cell_type": "code", 358 | "execution_count": null, 359 | "metadata": {}, 360 | "outputs": [], 361 | "source": [ 362 | "#include \n", 363 | "#include " 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": null, 369 | "metadata": {}, 370 | "outputs": [], 371 | "source": [ 372 | "int count_async = 0;\n", 373 | "struct test_async_executor\n", 374 | "{\n", 375 | " typedef hpx::execution::parallel_execution_tag execution_category;\n", 376 | "\n", 377 | " template \n", 378 | " static hpx::future::type>\n", 379 | " async_execute(F && f, Ts &&... ts) \n", 380 | " { \n", 381 | " ++count_async;\n", 382 | " return hpx::async(hpx::launch::async, std::forward(f),\n", 383 | " std::forward(ts)...);\n", 384 | " }\n", 385 | "};" 386 | ] 387 | }, 388 | { 389 | "cell_type": "code", 390 | "execution_count": null, 391 | "metadata": {}, 392 | "outputs": [], 393 | "source": [ 394 | "// Note that the exact way to specify this trait for an executor is in flux\n", 395 | "// and the code here is tied to the specific version of HPX on the test machine.\n", 396 | "namespace hpx::parallel::execution\n", 397 | "{\n", 398 | " template<>\n", 399 | " struct is_two_way_executor\n", 400 | " : std::true_type\n", 401 | " {};\n", 402 | "}" 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "execution_count": null, 408 | "metadata": {}, 409 | "outputs": [], 410 | "source": [ 411 | "#include " 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": null, 417 | "metadata": {}, 418 | "outputs": [], 419 | "source": [ 420 | "// This parallel tranformation of vector v\n", 421 | "// is done using using distributed parallelism.\n", 422 | "// NOTE: Ignore the warning\n", 423 | "test_async_executor e;\n", 424 | "hpx::transform (\n", 425 | " execution::par.on(e),\n", 426 | " begin(v), end(v), begin(v),\n", 427 | " [](int i) -> int\n", 428 | " {\n", 429 | " return i+1; \n", 430 | " });\n", 431 | "cout << \"count=\" << count_async << endl;" 432 | ] 433 | }, 434 | { 435 | "cell_type": "markdown", 436 | "metadata": {}, 437 | "source": [ 438 | "# Let’s Parallelize It – Adding Real Asynchrony\n", 439 | "\n", 440 | "Here we take a step back. Instead of using a pre-designed parallel operation on a vector, we instead introduce task-level parallelism to an existing program.\n", 441 | "\n", 442 | "Calculate Fibonacci numbers in parallel (1st attempt)" 443 | ] 444 | }, 445 | { 446 | "cell_type": "code", 447 | "execution_count": null, 448 | "metadata": {}, 449 | "outputs": [], 450 | "source": [ 451 | "uint64_t fibonacci(uint64_t n)\n", 452 | "{\n", 453 | " // if we know the answer, we return the value\n", 454 | " if (n < 2) return n;\n", 455 | " // asynchronously calculate one of the sub-terms\n", 456 | " future f = async(launch::async, &fibonacci, n-2);\n", 457 | " // synchronously calculate the other sub-term\n", 458 | " uint64_t r = fibonacci(n-1);\n", 459 | " // wait for the future and calculate the result\n", 460 | " return f.get() + r;\n", 461 | "}" 462 | ] 463 | }, 464 | { 465 | "cell_type": "code", 466 | "execution_count": null, 467 | "metadata": {}, 468 | "outputs": [], 469 | "source": [ 470 | "cout << fibonacci(10) << endl;" 471 | ] 472 | }, 473 | { 474 | "cell_type": "markdown", 475 | "metadata": {}, 476 | "source": [ 477 | "# Let’s Parallelize It – Introducing Control of Grain Size\n", 478 | "Parallel calculation, switching to serial execution below given threshold" 479 | ] 480 | }, 481 | { 482 | "cell_type": "code", 483 | "execution_count": null, 484 | "metadata": {}, 485 | "outputs": [], 486 | "source": [ 487 | "const int threshold = 20;\n", 488 | "\n", 489 | "uint64_t fibonacci_serial(uint64_t n)\n", 490 | "{\n", 491 | " if (n < 2) return n;\n", 492 | " uint64_t f1 = fibonacci_serial(n-2);\n", 493 | " uint64_t f2 = fibonacci_serial(n-1);\n", 494 | " return f1 + f2;\n", 495 | "}\n", 496 | "\n", 497 | "uint64_t fibonacci2(uint64_t n)\n", 498 | "{\n", 499 | " if (n < 2) return n;\n", 500 | " if (n < threshold) return fibonacci_serial(n);\n", 501 | " // asynchronously calculate one of the sub-terms\n", 502 | " future f = async(launch::async, &fibonacci2, n-2);\n", 503 | " // synchronously calculate the other sub-term\n", 504 | " uint64_t r = fibonacci2(n-1);\n", 505 | " // wait for the future and calculate the result\n", 506 | " return f.get() + r;\n", 507 | "}" 508 | ] 509 | }, 510 | { 511 | "cell_type": "code", 512 | "execution_count": null, 513 | "metadata": {}, 514 | "outputs": [], 515 | "source": [ 516 | "cout << fibonacci2(22) << endl;" 517 | ] 518 | }, 519 | { 520 | "cell_type": "markdown", 521 | "metadata": {}, 522 | "source": [ 523 | "# Let’s Parallelize It – Apply Futurization\n", 524 | "Parallel way, futurize algorithm to remove suspension points" 525 | ] 526 | }, 527 | { 528 | "cell_type": "code", 529 | "execution_count": null, 530 | "metadata": {}, 531 | "outputs": [], 532 | "source": [ 533 | "future fibonacci3(uint64_t n)\n", 534 | "{\n", 535 | " if(n < 2) return make_ready_future(n);\n", 536 | " if(n < threshold) return make_ready_future(fibonacci_serial(n));\n", 537 | "\n", 538 | " future f = async(launch::async, &fibonacci3, n-2);\n", 539 | " future r = fibonacci3(n-1);\n", 540 | "\n", 541 | " return dataflow(\n", 542 | " [](future f1, future f2) {\n", 543 | " return f1.get() + f2.get();\n", 544 | " },\n", 545 | " f, r);\n", 546 | "}" 547 | ] 548 | }, 549 | { 550 | "cell_type": "code", 551 | "execution_count": null, 552 | "metadata": {}, 553 | "outputs": [], 554 | "source": [ 555 | "cout << fibonacci3(22).get() << endl;" 556 | ] 557 | }, 558 | { 559 | "cell_type": "markdown", 560 | "metadata": {}, 561 | "source": [ 562 | "# Let’s Parallelize It – Unwrap Argument Futures" 563 | ] 564 | }, 565 | { 566 | "cell_type": "code", 567 | "execution_count": null, 568 | "metadata": {}, 569 | "outputs": [], 570 | "source": [ 571 | "using hpx::util::unwrapping;\n", 572 | "\n", 573 | "future fibonacci4(uint64_t n)\n", 574 | "{\n", 575 | " if(n < 2) return make_ready_future(n);\n", 576 | " if(n < threshold) return make_ready_future(fibonacci_serial(n));\n", 577 | "\n", 578 | " future f = async(launch::async, &fibonacci4, n-2);\n", 579 | " future r = fibonacci4(n-1);\n", 580 | "\n", 581 | " return dataflow(\n", 582 | " hpx::unwrapping([](uint64_t f1, uint64_t f2)->uint64_t {\n", 583 | " return f1+f2;\n", 584 | " }),\n", 585 | " f, r);\n", 586 | "}" 587 | ] 588 | }, 589 | { 590 | "cell_type": "code", 591 | "execution_count": null, 592 | "metadata": {}, 593 | "outputs": [], 594 | "source": [ 595 | "cout << fibonacci4(22).get() << endl;" 596 | ] 597 | }, 598 | { 599 | "cell_type": "markdown", 600 | "metadata": { 601 | "collapsed": true, 602 | "jupyter": { 603 | "outputs_hidden": true 604 | } 605 | }, 606 | "source": [ 607 | "### Excercise: Parallelize a sort\n", 608 | "Test what you've learned. See if you can speed up the quicksort program below by find a place to:\n", 609 | "1. parallelize the code with async\n", 610 | "2. use parallel transforms" 611 | ] 612 | }, 613 | { 614 | "cell_type": "code", 615 | "execution_count": null, 616 | "metadata": {}, 617 | "outputs": [], 618 | "source": [ 619 | "#include \n", 620 | "#include \n", 621 | "#include \n", 622 | "#include \n", 623 | "#include \n", 624 | "typedef std::vector::iterator viter;" 625 | ] 626 | }, 627 | { 628 | "cell_type": "code", 629 | "execution_count": null, 630 | "metadata": {}, 631 | "outputs": [], 632 | "source": [ 633 | "void myqsort(viter first, viter last) {\n", 634 | " assert(first <= last);\n", 635 | " ptrdiff_t range = last - first;\n", 636 | " if(range > 1) {\n", 637 | " auto pivot_value = first[rand() % range];\n", 638 | " // Try converting this to use a parallel algorithm\n", 639 | " auto middle1 = std::partition(first, last, [&](auto em) { return em < pivot_value;});\n", 640 | " assert(middle1 <= last);\n", 641 | " auto middle2 = std::partition(middle1, last, [&](auto em) { return em <= pivot_value;});\n", 642 | " assert(middle2 <= last);\n", 643 | "\n", 644 | " // try invoking this using hpx::async\n", 645 | " myqsort(first,middle1);\n", 646 | " myqsort(middle2,last);\n", 647 | " }\n", 648 | "}\n", 649 | "vector vv{20};\n", 650 | "for(int i=0;i<20;i++) vv.push_back(rand() % 100);\n", 651 | "for(int val : vv) cout << val << \" \";\n", 652 | "cout << endl;\n", 653 | "myqsort(begin(vv),end(vv));\n", 654 | "for(int val : vv) cout << val << \" \";\n", 655 | "cout << endl;" 656 | ] 657 | }, 658 | { 659 | "cell_type": "code", 660 | "execution_count": null, 661 | "metadata": {}, 662 | "outputs": [], 663 | "source": [] 664 | } 665 | ], 666 | "metadata": { 667 | "kernelspec": { 668 | "display_name": "C++17", 669 | "language": "C++", 670 | "name": "cling-cpp17" 671 | }, 672 | "language_info": { 673 | "codemirror_mode": "c++", 674 | "file_extension": ".c++", 675 | "mimetype": "text/x-c++src", 676 | "name": "c++" 677 | } 678 | }, 679 | "nbformat": 4, 680 | "nbformat_minor": 4 681 | } 682 | -------------------------------------------------------------------------------- /notebooks/py11demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# First, import the py11 module\n", 8 | "\n", 9 | "The underlying technology that makes this work on pybind11 (https://github.com/pybind/pybind11)\n", 10 | "\n", 11 | "It compiles individual functions in C++ to provide an more dynamic approach to C++ programming.\n", 12 | "\n", 13 | "First step, import the following symbols..." 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "!rm -fr ~/tmp\n", 23 | "!mkdir -p ~/tmp" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "from py11 import py11, smap, svec" 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "To create a C++ function that's callable from Python, use the @py11 decorator and\n", 40 | "put your code in the docstring. You\n", 41 | "can supply it with a list of headers needed. You can modify the source and\n", 42 | "re-execute the cell if you want different output." 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "@py11(headers=[''])\n", 52 | "def hello():\n", 53 | " \"\"\"\n", 54 | " std::cout << \"Hello, world\" << std::endl;\n", 55 | " std::cerr << \"Goodbye, world\" << std::endl;\n", 56 | " \"\"\"" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "We can now call this function directly from Python. It won't recompile again unless we change the source code." 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "hello()" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "We can pass arguments to the function and receive arguments back. To do this, we use\n", 80 | "Python's syntax for declaring types." 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "@py11()\n", 90 | "def sumi(a : int,b : int)->int:\n", 91 | " \"\"\"\n", 92 | " // add 2 args\n", 93 | " return a+b;\n", 94 | " \"\"\"" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": {}, 101 | "outputs": [], 102 | "source": [ 103 | "sumi(20,22)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": {}, 109 | "source": [ 110 | "Static variables can be used to remember state." 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "@py11()\n", 120 | "def count()->int:\n", 121 | " \"\"\"\n", 122 | " static int counter = 0; // remember state\n", 123 | " return counter++;\n", 124 | " \"\"\"" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "for i in range(5):\n", 134 | " print(count())" 135 | ] 136 | }, 137 | { 138 | "cell_type": "markdown", 139 | "metadata": {}, 140 | "source": [ 141 | "If you want to pass a more complex data structure, like an std::vector, use svec." 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "@py11(headers=[\"\"])\n", 151 | "def sumv(v : svec[int])->int:\n", 152 | " \"\"\"\n", 153 | " int sum=0;\n", 154 | " for(auto i=v.begin(); i != v.end(); ++i)\n", 155 | " sum += *i;\n", 156 | " return sum;\n", 157 | " \"\"\"" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "sumv([1,2,3,4])" 167 | ] 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": {}, 172 | "source": [ 173 | "Something similar works for maps..." 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "@py11(header=[''])\n", 183 | "def summ(m : smap[str,int])->int:\n", 184 | " \"\"\"\n", 185 | " int sum = 0;\n", 186 | " for(auto i=m.begin();i != m.end();++i) {\n", 187 | " sum += i->second;\n", 188 | " }\n", 189 | " return sum;\n", 190 | " \"\"\"\n", 191 | "\n", 192 | "print(summ({\"a\":3,\"b\":10}))" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "It is possible to use pybind11 to throw an exception from C++ into Python." 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": null, 205 | "metadata": {}, 206 | "outputs": [], 207 | "source": [ 208 | "@py11()\n", 209 | "def get_and_set(k : str, v : int, p : bool)->int:\n", 210 | " \"\"\"\n", 211 | " static std::map dict;\n", 212 | " if(!p)\n", 213 | " if(dict.find(k) == dict.end())\n", 214 | " throw py::key_error(k);\n", 215 | " int r = dict[k];\n", 216 | " if(p)dict[k] = v;\n", 217 | " return r;\n", 218 | " \n", 219 | " \"\"\"" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": null, 225 | "metadata": {}, 226 | "outputs": [], 227 | "source": [ 228 | "get_and_set(\"a\",3,True)" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": null, 234 | "metadata": {}, 235 | "outputs": [], 236 | "source": [ 237 | "get_and_set(\"a\",0,False)" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": null, 243 | "metadata": {}, 244 | "outputs": [], 245 | "source": [ 246 | "try:\n", 247 | " get_and_set(\"b\",0,False)\n", 248 | "except KeyError as ke:\n", 249 | " print(\"Not a valid key:\",ke)" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "Recursion works..." 257 | ] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "execution_count": null, 262 | "metadata": {}, 263 | "outputs": [], 264 | "source": [ 265 | "@py11()\n", 266 | "def fib(n : int)->int:\n", 267 | " \"\"\"\n", 268 | " if(n < 2) return n;\n", 269 | " return fib(n-1)+fib(n-2);\n", 270 | " \"\"\"" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "If we define a Python version of this same function, we can run a benchmark..." 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "execution_count": null, 283 | "metadata": {}, 284 | "outputs": [], 285 | "source": [ 286 | "def fib2(n):\n", 287 | " if n < 2:\n", 288 | " return n\n", 289 | " return fib2(n-1)+fib2(n-2)" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": null, 295 | "metadata": {}, 296 | "outputs": [], 297 | "source": [ 298 | "def timer(fun,*args):\n", 299 | " from time import time\n", 300 | " t1 = time()\n", 301 | " fun(*args)\n", 302 | " t2 = time()\n", 303 | " print(\"time:\",t2-t1)" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "metadata": {}, 309 | "source": [ 310 | "You should find that fib is much faster than fib2." 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": null, 316 | "metadata": {}, 317 | "outputs": [], 318 | "source": [ 319 | "timer(fib,34)\n", 320 | "timer(fib2,34)" 321 | ] 322 | }, 323 | { 324 | "cell_type": "markdown", 325 | "metadata": {}, 326 | "source": [ 327 | "If we want to call one @py11() function from another, we can. However, we need to specify what\n", 328 | "we are doing by means of the funs parameter." 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": null, 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [ 337 | "@py11(funs=[fib],headers=[\"\"])\n", 338 | "def print_fib(n:int)->None:\n", 339 | " \"\"\"\n", 340 | " std::cout << \"fib(\" << n << \") = \" << fib(n) << std::endl;\n", 341 | " \"\"\"" 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": null, 347 | "metadata": {}, 348 | "outputs": [], 349 | "source": [ 350 | "print_fib(15)" 351 | ] 352 | }, 353 | { 354 | "cell_type": "markdown", 355 | "metadata": {}, 356 | "source": [ 357 | "Note that if we redefine fib, print_fib() will automatically\n", 358 | "update to use the new version." 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": null, 364 | "metadata": {}, 365 | "outputs": [], 366 | "source": [ 367 | "@py11()\n", 368 | "def fib(n : int)->int:\n", 369 | " \"\"\"\n", 370 | " if(n < 0) return n;\n", 371 | " return fib(n-1)+fib(n-2);\n", 372 | " \"\"\"" 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": null, 378 | "metadata": {}, 379 | "outputs": [], 380 | "source": [ 381 | "print_fib(15)" 382 | ] 383 | }, 384 | { 385 | "cell_type": "markdown", 386 | "metadata": {}, 387 | "source": [ 388 | "If we want to change the compile flags, we can." 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": null, 394 | "metadata": {}, 395 | "outputs": [], 396 | "source": [ 397 | "from py11 import py11, create_type, set_flags\n", 398 | "\n", 399 | "# Set the compile flags\n", 400 | "set_flags(\"-std=c++17 -L/usr/local/lib -lhpx -lhpx_core -Wl,-rpath=/usr/local/lib\")\n", 401 | "\n", 402 | "# Create your own types\n", 403 | "create_type(\"func\",\"std::function\")" 404 | ] 405 | }, 406 | { 407 | "cell_type": "markdown", 408 | "metadata": {}, 409 | "source": [ 410 | "Sometimes you need to set the LD_LIBRARY_PATH" 411 | ] 412 | }, 413 | { 414 | "cell_type": "markdown", 415 | "metadata": {}, 416 | "source": [ 417 | "HPX is an advanced parallel threading library. However, to use it, you have to have a\n", 418 | "special threading environment. To make this work, we will create a \"wrapper function.\"\n", 419 | "This function needs to take a std::function as an input argument." 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": null, 425 | "metadata": {}, 426 | "outputs": [], 427 | "source": [ 428 | "@py11(headers=[\"\"],recompile=True)\n", 429 | "def hpx_wrapper(f : func)->None:\n", 430 | " \"\"\"\n", 431 | " const char *num = getenv(\"HPX_NUM_THREADS\");\n", 432 | " int num_threads = num == 0 ? 4 : atoi(num);\n", 433 | " std::cout << \"Using \" << num_threads << \" threads.\" << std::endl;\n", 434 | " hpx_global::submit_work(num_threads,f);\n", 435 | " \"\"\"" 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": null, 441 | "metadata": {}, 442 | "outputs": [], 443 | "source": [ 444 | "@py11(headers=[\"\"],recompile=True,wrap=hpx_wrapper)\n", 445 | "def do_fut()->None:\n", 446 | " \"\"\"\n", 447 | " auto f = hpx::async([](){ return 5; });\n", 448 | " std::cout << \"f=\" << f.get() << std::endl;\n", 449 | " \"\"\"" 450 | ] 451 | }, 452 | { 453 | "cell_type": "code", 454 | "execution_count": null, 455 | "metadata": {}, 456 | "outputs": [], 457 | "source": [ 458 | "do_fut()" 459 | ] 460 | }, 461 | { 462 | "cell_type": "code", 463 | "execution_count": null, 464 | "metadata": {}, 465 | "outputs": [], 466 | "source": [ 467 | "create_type(\"future\",\"hpx::future\",is_template=True)" 468 | ] 469 | }, 470 | { 471 | "cell_type": "code", 472 | "execution_count": null, 473 | "metadata": { 474 | "scrolled": true 475 | }, 476 | "outputs": [], 477 | "source": [ 478 | "@py11(headers=[\"\"],recompile=True,wrap=hpx_wrapper)\n", 479 | "def hpx_fib(n : int)->int:\n", 480 | " \"\"\"\n", 481 | " if(n < 2)\n", 482 | " return n;\n", 483 | " if(n < 25)\n", 484 | " return hpx_fib(n-1)+hpx_fib(n-2);\n", 485 | " hpx::future f1 = hpx::async(hpx_fib,n-1);\n", 486 | " int f2 = hpx_fib(n-2);\n", 487 | " return f1.get() + f2;\n", 488 | " \"\"\"" 489 | ] 490 | }, 491 | { 492 | "cell_type": "code", 493 | "execution_count": null, 494 | "metadata": {}, 495 | "outputs": [], 496 | "source": [ 497 | "nfib = 34\n", 498 | "(hpx_fib(nfib), fib2(nfib))" 499 | ] 500 | }, 501 | { 502 | "cell_type": "code", 503 | "execution_count": null, 504 | "metadata": {}, 505 | "outputs": [], 506 | "source": [ 507 | "nfib = 34\n", 508 | "timer(hpx_fib,nfib)\n", 509 | "timer(fib2, nfib)" 510 | ] 511 | }, 512 | { 513 | "cell_type": "code", 514 | "execution_count": null, 515 | "metadata": {}, 516 | "outputs": [], 517 | "source": [ 518 | "def timer2(fun,args,zargs):\n", 519 | " from time import time\n", 520 | " t1 = time()\n", 521 | " fun(*args)\n", 522 | " t2 = time()\n", 523 | " fun(*zargs)\n", 524 | " t3 = time()\n", 525 | " \n", 526 | " del1 = t2-t1 # time with args\n", 527 | " del2 = t3-t2 # time with zargs\n", 528 | " \n", 529 | " delt = del1 - del2\n", 530 | " print(\"time:\",delt)" 531 | ] 532 | }, 533 | { 534 | "cell_type": "code", 535 | "execution_count": null, 536 | "metadata": {}, 537 | "outputs": [], 538 | "source": [ 539 | "nfib = 34\n", 540 | "timer2(hpx_fib,[nfib],[1])\n", 541 | "timer2(fib2, [nfib],[1])" 542 | ] 543 | }, 544 | { 545 | "cell_type": "markdown", 546 | "metadata": {}, 547 | "source": [ 548 | "Sometimes calling C++ can kill the notebook kernel. To avoid that problem, we can run in a thread." 549 | ] 550 | }, 551 | { 552 | "cell_type": "code", 553 | "execution_count": null, 554 | "metadata": {}, 555 | "outputs": [], 556 | "source": [ 557 | "def run_fork(f,*args):\n", 558 | " import os\n", 559 | " pid = os.fork()\n", 560 | " if pid==0:\n", 561 | " f(*args)\n", 562 | " os._exit(0)\n", 563 | " else:\n", 564 | " while True:\n", 565 | " wpid, wstatus = os.wait()\n", 566 | " if wpid == pid:\n", 567 | " if wstatus == 0:\n", 568 | " pass\n", 569 | " print(\"status:\",wstatus)\n", 570 | " return" 571 | ] 572 | }, 573 | { 574 | "cell_type": "code", 575 | "execution_count": null, 576 | "metadata": {}, 577 | "outputs": [], 578 | "source": [ 579 | "@py11()\n", 580 | "def segv():\n", 581 | " \"\"\"\n", 582 | " int *i=0;\n", 583 | " i[0]=1;\n", 584 | " \"\"\"" 585 | ] 586 | }, 587 | { 588 | "cell_type": "code", 589 | "execution_count": null, 590 | "metadata": {}, 591 | "outputs": [], 592 | "source": [ 593 | "run_fork(segv)" 594 | ] 595 | }, 596 | { 597 | "cell_type": "code", 598 | "execution_count": null, 599 | "metadata": {}, 600 | "outputs": [], 601 | "source": [ 602 | "@py11(headers=[\"\"])\n", 603 | "def prvec(v : svec[float])->None:\n", 604 | " \"\"\"\n", 605 | " std::cout << \"prvec\" << std::endl;\n", 606 | " for(auto i : v) \n", 607 | " std::cout << i << \" \";\n", 608 | " std::cout << std::endl;\n", 609 | " \"\"\"\n", 610 | "prvec([1.0,2.0,3])" 611 | ] 612 | }, 613 | { 614 | "cell_type": "markdown", 615 | "metadata": {}, 616 | "source": [ 617 | "Now for some fancy stuff... defining executors that (in principle) can work on more than one locality" 618 | ] 619 | }, 620 | { 621 | "cell_type": "code", 622 | "execution_count": null, 623 | "metadata": {}, 624 | "outputs": [], 625 | "source": [ 626 | "create_type(\"executor\",\"hpx::compute::host::block_executor<>\")\n", 627 | "\n", 628 | "@py11(headers=[\"\",\"\"])\n", 629 | "def getexec()->executor:\n", 630 | " \"\"\"\n", 631 | " auto host_targets = hpx::compute::host::get_local_targets();\n", 632 | " typedef hpx::compute::host::block_executor<> executor_type;\n", 633 | " executor_type exec(host_targets);\n", 634 | " \n", 635 | " for(auto host : host_targets)\n", 636 | " std::cout << \"(\" << std::get<0>(host.num_pus()) << \",\" << std::get<1>(host.num_pus()) << \")\" << std::endl;\n", 637 | " \n", 638 | " return exec;\n", 639 | " \"\"\"" 640 | ] 641 | }, 642 | { 643 | "cell_type": "markdown", 644 | "metadata": {}, 645 | "source": [ 646 | "Fill an array" 647 | ] 648 | }, 649 | { 650 | "cell_type": "code", 651 | "execution_count": null, 652 | "metadata": {}, 653 | "outputs": [], 654 | "source": [ 655 | "@py11(wrap=hpx_wrapper,funs=[prvec,getexec],headers=[\n", 656 | " \"\",\n", 657 | " \"\",\n", 658 | " \"\",\n", 659 | " \"\"\n", 660 | " ])\n", 661 | "def fill_example()->None:\n", 662 | " \"\"\"\n", 663 | " auto exec = getexec();\n", 664 | " \n", 665 | " std::vector vd;\n", 666 | " for(int i=0;i<5;i++) vd.push_back(1.f);\n", 667 | " prvec(vd);\n", 668 | " hpx::fill(hpx::execution::par.on(exec),vd.begin(),vd.end(),2.0f);\n", 669 | " prvec(vd);\n", 670 | " \"\"\"\n", 671 | "\n", 672 | "fill_example()" 673 | ] 674 | }, 675 | { 676 | "cell_type": "code", 677 | "execution_count": null, 678 | "metadata": {}, 679 | "outputs": [], 680 | "source": [ 681 | "@py11(wrap=hpx_wrapper,funs=[prvec,getexec],headers=[\n", 682 | " \"\",\n", 683 | " \"\",\n", 684 | " \"\",\n", 685 | " \"\"\n", 686 | " ])\n", 687 | "def rev_example()->None:\n", 688 | " \"\"\"\n", 689 | " auto exec = getexec();\n", 690 | " \n", 691 | " std::vector vd;\n", 692 | " for(int i=0;i<10;i++) vd.push_back(i);\n", 693 | " prvec(vd);\n", 694 | " hpx::reverse(hpx::execution::par.on(exec),vd.begin(),vd.end());\n", 695 | " prvec(vd);\n", 696 | " \"\"\"\n", 697 | "\n", 698 | "rev_example()" 699 | ] 700 | }, 701 | { 702 | "cell_type": "code", 703 | "execution_count": null, 704 | "metadata": {}, 705 | "outputs": [], 706 | "source": [ 707 | "@py11(wrap=hpx_wrapper,funs=[prvec,getexec],headers=[\n", 708 | " \"\",\n", 709 | " \"\",\n", 710 | " \"\",\n", 711 | " \"\"\n", 712 | " ])\n", 713 | "def min_example()->None:\n", 714 | " \"\"\"\n", 715 | " auto exec = getexec();\n", 716 | " \n", 717 | " std::vector vd;\n", 718 | " for(int i=0;i<10;i++) vd.push_back(i+300);\n", 719 | " prvec(vd);\n", 720 | " auto ptr = hpx::min_element(hpx::execution::par.on(exec),\n", 721 | " vd.begin(),vd.end(),std::less());\n", 722 | " std::cout << *ptr << std::endl;\n", 723 | " ptr = hpx::max_element(hpx::execution::par.on(exec),\n", 724 | " vd.begin(),vd.end(),std::less());\n", 725 | " std::cout << *ptr << std::endl;\n", 726 | " \"\"\"\n", 727 | "\n", 728 | "min_example()" 729 | ] 730 | }, 731 | { 732 | "cell_type": "markdown", 733 | "metadata": {}, 734 | "source": [ 735 | "Exercise: Make this routine run in parallel with HPX" 736 | ] 737 | }, 738 | { 739 | "cell_type": "code", 740 | "execution_count": null, 741 | "metadata": {}, 742 | "outputs": [], 743 | "source": [ 744 | "@py11(wrap=hpx_wrapper,headers=[\"\"])\n", 745 | "def myqsort(v : svec[int])->svec[int]:\n", 746 | " \"\"\"\n", 747 | " if(v.size() < 2)\n", 748 | " return v;\n", 749 | " int pivot = v[rand() % v.size()];\n", 750 | " std::vector lo, hi, eq;\n", 751 | " for(int i=0;i pivot)\n", 755 | " hi.push_back(v[i]);\n", 756 | " else\n", 757 | " eq.push_back(v[i]);\n", 758 | " }\n", 759 | " lo = myqsort(lo);\n", 760 | " hi = myqsort(hi);\n", 761 | " std::vector result;\n", 762 | " result.insert(result.end(),lo.begin(),lo.end());\n", 763 | " result.insert(result.end(),eq.begin(),eq.end());\n", 764 | " result.insert(result.end(),hi.begin(),hi.end());\n", 765 | " return result;\n", 766 | " \"\"\"\n", 767 | "\n", 768 | "from random import randint\n", 769 | "inp = [randint(1,100) for v in range(20)]\n", 770 | "out = myqsort(inp)\n", 771 | "print(inp)\n", 772 | "print(out)\n", 773 | "\n", 774 | "# check result...\n", 775 | "for i in range(1,len(out)):\n", 776 | " assert out[i-1] <= out[i]\n", 777 | "vals = {}\n", 778 | "for v in inp:\n", 779 | " if v not in vals:\n", 780 | " vals[v] = 0\n", 781 | " vals[v] += 1\n", 782 | "for v in out:\n", 783 | " # if vals[v] is not defined, our sort messed up\n", 784 | " vals[v] -= 1\n", 785 | "for v in vals.values():\n", 786 | " assert v == 0 # should have all the same values in output" 787 | ] 788 | }, 789 | { 790 | "cell_type": "code", 791 | "execution_count": null, 792 | "metadata": {}, 793 | "outputs": [], 794 | "source": [] 795 | } 796 | ], 797 | "metadata": { 798 | "kernelspec": { 799 | "display_name": "Python 3 (ipykernel)", 800 | "language": "python", 801 | "name": "python3" 802 | }, 803 | "language_info": { 804 | "codemirror_mode": { 805 | "name": "ipython", 806 | "version": 3 807 | }, 808 | "file_extension": ".py", 809 | "mimetype": "text/x-python", 810 | "name": "python", 811 | "nbconvert_exporter": "python", 812 | "pygments_lexer": "ipython3", 813 | "version": "3.10.6" 814 | } 815 | }, 816 | "nbformat": 4, 817 | "nbformat_minor": 2 818 | } 819 | --------------------------------------------------------------------------------