跳轉到

Numerical Software Development

Fundamental Engineering⚓︎

Shebang⚓︎

#!/bin/bash中的#!在檔案中存在Shebang的情況下,類Unix作業系統的程式載入器會分析Shebang後的內容,將這些內容作為直譯器指令,並呼叫該指令,並將載有Shebang的檔案路徑作為該直譯器的參數。

Variable⚓︎

Shell Variable (local)⚓︎

Bash Session
$ shell_var="shell_value"

Environment Variable (global)⚓︎

Bash Session
$ env_var="env_value"
$ export env_var
$ export env_var2="other_env_value"

Source⚓︎

dosomething.sh:

Bash
#!/bin/bash
export MYENVVAR="MYENVVAR is set to what I want"
echo "do something"
Without source(Child process cannot modify the current environment variable):
Bash Session
$ unset MYENVVAR
$ ./dosomething.sh
$ echo ${MYENVVAR:-"MYENVVAR is not set"}
do something
MYENVVAR is not set
With source(Child process can modify the current environment variable):
Bash Session
$ unset MYENVVAR
$ source ./dosomething.sh
$ echo ${MYENVVAR:-"MYENVVAR is not set"}
do something
MYENVVAR is set to what I want

Redirection⚓︎

Simple Redirection⚓︎

Bash Session
$ echo "a line output" > line.log
$ cat line.log
a line output

Stdout & Stderr Redirection⚓︎

Bash Session
$ cp nothisfile.txt another.txt 2>&1 > /dev/null
cp: nothisfile.txt: No such file or directory
$ cp nothisfile.txt another.txt > /dev/null 2>&1
$ cat another.txt
cat: another.txt: No such file or directory

Stderr to Null Device⚓︎

Bash Session
$ # without redirecting stderr we see unwanted messages
$ var=$(grep impossiblestring *)
grep: bind1: Is a directory
grep: build: Is a directory
grep: gtest: Is a directory
grep: make1: Is a directory
grep: make2: Is a directory
grep: make3: Is a directory
grep: make4: Is a directory
grep: nsd: Is a directory
grep: repo1: Is a directory
$ echo $var
Bash Session
$ # throw stderr to null device and we get only the wanted information
$ var=$(grep impossiblestring * 2> /dev/null)
$ echo $var

Conditional Branching (If/Else)⚓︎

Bash
#!/bin/bash
if [[ "$(uname)" == "Darwin" ]] ; then
  NP=${NP:-$(sysctl -n hw.ncpu)}
elif [[ "$(uname)" == "Linux" ]] ; then
  NP=${NP:-$(cat /proc/cpuinfo | grep processor | wc -l)}
else
  NP=${NP:=1}
fi
echo "NP may be set to $NP"
Bash Session
$ uname
Darwin
$ ./shownp.sh
NP may be set to 8

Function⚓︎

Bash
#!/bin/bash
runcmd () {
  echo "run command: ${@:2}"
  { time "${@:2}" ; } > $1 2>&1
  echo "done; log file: $(cd "$(dirname $1)" && pwd)/$1"
}
runcmd line1.log echo "first command"
runcmd line2.log echo "second command"
Bash Session
$ ./bashfunction.sh
run command: echo first command
done; log file: /Users/yungyuc/hack/code/nsd/notebook/20au_nctu/02_engineering/line1.log
run command: echo second command
done; log file: /Users/yungyuc/hack/code/nsd/notebook/20au_nctu/02_engineering/line2.log
$ cat line1.log
first command

real  0m0.000s
user  0m0.000s
sys   0m0.000s
$ cat line2.log
second command

real  0m0.000s
user  0m0.000s
sys   0m0.000s

Makeflie⚓︎

Make could trace the timestamp of the source file automatically.

Makefile Format⚓︎

Rule:

Makefile
CXX = g++

target ... : prerequisites ...
    recipe
    ...
    ...
https://seisman.github.io/how-to-write-makefile/overview.html

Automatic Variables and Implicit Rule⚓︎

  • $@ is the file name of the target of the rule.

  • $^ is the file names of all the prerequisites.

  • $< is the file name of the first prerequisite.

  • % in the target will match any non-empty characters, and it is expanded in the prerequisite.

Makefile
CXX = g++

hello: hello.o hellomain.o
        $(CXX) $^ -o $@

%.o: %.cpp hello.hpp
        $(CXX) -c $< -o $@
Bash Session
$ rm -f hello *.o
$ make
g++ -c hello.cpp -o hello.o
g++ -c hellomain.cpp -o hellomain.o
g++ hello.o hellomain.o -o hello

Phony targets⚓︎

Makefile
.PHONY: clean
clean:
        rm -rf hello *.o
Bash Session
$ make clean
rm -rf hello *.o

CMake⚓︎

  • CMake is a two-pass build tool.
  • First pass reads the input file CMakeLists.txt and generates files for the second pass.
  • The second pass uses a different build tool (may be make) to build the software.
  • Useful for cross-platform building.
  • Bash and make can handle a little bit of the cross-platform. But the if/else is not easy to maintain.

Python and Numpy⚓︎

Python⚓︎

Modeline⚓︎

vim內建的功能,可以知道程式如何排版。

Python
...
# vim: set ff=unix fenc=utf8 ft=python et sw=4 ts=4 sts=4 tw=79:

One-Liner⚓︎

Bash Session
$ python3 -c 'print(len(open("pstake.py").readlines()), "lines")'
811 lines

Module⚓︎

當python檔不是腳本時,if __main__=="name" 就不會有反應。 如果想直接執行腳本中的if __main__=="name"。 可以使用-m

Bash Session
$ python3 step3/__init__.py pstake.py
Traceback (most recent call last):
  File "/Users/yungyuc/work/web/ynote/nsd/02numpy/code/step3/__init__.py", line 12, in <module>
    from ._core import count_line
ImportError: attempted relative import with no known parent package
$ python3 -m step3 pstake.py
811 lines in pstake.py

Note

題外話,雙底線__的英文叫做double underscore,或是有更簡單的叫法,dunder。

Numpy⚓︎

Basic Meta-Data⚓︎

  • itemsize: number of bytes of an element
    Python
    array = np.array([[0, 1, 2], [3, 4, 5]])
    print("itemsize:", array.itemsize)
    #$ itemsize: 8
    
  • nbytes: number of bytes of all elements

    Python
    array = np.array([[0, 1, 2], [3, 4, 5]])
    print("nbytes:", array.nbytes)
    #$ nbytes: 48
    

  • dtype:

dtype (object) dtype string name C++ type name
numpy.bool_ "bool" bool
numpy.int8 "int8" int8_t
numpy.int16 "int16" int16_t
numpy.int32 "int32" int32_t
numpy.int64 "int64" int64_t
numpy.uint8 "uint8" uint8_t
numpy.uint16 "uint16" uint16_t
numpy.uint32 "uint32" uint32_t
numpy.uint64 "uint64" uint64_t
numpy.float32 "float32" float
numpy.float64 "float64" double

Construction⚓︎

  • fulls():
    Python
    empty_array = np.empty(4)
    empty_array.fill(7)
    print(empty_array)
    [7. 7. 7. 7.]
    filled_real_array = np.full(4, 7.0)
    print(filled_real_array)
    [7. 7. 7. 7.]
    

Slicing⚓︎

  • Copy
    Python
    # Get a slice from the original array.
    sub_array = array[:5]
    # Copy all elements of the sub-array to a new one.
    sub_array = sub_array.copy()
    

Reference⚓︎

  1. Yung-Yu's Notes