Overview

HARK-Python3 is a package that enables Python code execution written using pybind11 for HARK.

HARK-Python3 provides two functions:

  1. Data visualization nodes using matplotlib, a powerful visualization module for python
  2. A wrapper to develop a HARK node using python3.
_images/harkpython-overview.png

Benefits of HARK-Python3

Rich visualization

The visualization nodes implemented by HARK’s basic packages is limited. Currently only DisplayLocalization used for visualizing localization results is provided. By using HARK-Python3 package, the following visualization modules can now be used:

  • waveform(plotWaveform3)
  • spectrogram(plotSpec3)
  • localization(plotSource3)
  • power of the MUSIC spectrum(plotMUSICSpec3)

Quick development of the new node

PyCodeExecutor3 allows you to utilize your own code. To do so, make sure to begin your code as follows:

from harkpython import harkbasenode
class HarkNode (harkbasenode.HarkBaseNode):
    def __init__(self):
        # define the output names and types of your node as tuples here.
    def calculate(self):
        # write your code here.

Then, build a network that uses PyCodeExecutor3.

Installation

For Windows users

  1. Install HARK for Windows using the installer. See Windows HARK installation instructions for details.

For Ubuntu users

  1. Add HARK repository and install Basic HARK Packages. See Linux HARK installation instructions for details.

  2. Install HARK-Python3

    sudo apt install hark-python3 python3-numpy python3-matplotlib
    

Getting Started

Tutorial 1: Run examples

Download HARK-Python3 examples

Run the following command

batchflow plotSource3Network.n plotSourceExample.xml
batchflow plotSpec3Network.n 2SPK-jp.wav
batchflow plotWaveform3Network.n 2SPK-jp.wav
batchflow plotMUSICSpec3Network.n 2SPK-jp.wav

Then, you will see graphs drawn by matplotlib.

Tutorial 2: Implement your node with python

The goal is to calculate \(input1^3 + input2^5\)

1. Place 2 Constants and a single PyCodeExecutor3 node into your HARK network. Right-click on PyCodeExecutor3’s output terminal, select “Set as Output”, and change the default value to “output”. Add input terminals “input1” and “input2” to PyCodeExecutor3 by right-clicking on PyCodeExecutor3’s node and selecting “Add Input”. Once completed, connect all nodes and save it as tutorial2.n.

_images/harkpython-simple.png
  1. Set parameters
  1. node_Constant_1: int 3
  2. node_Constant_2: int 5
  3. PyCodeExecutor3: default.
  1. Write the code depicted bellow. Save it as samplecode.py in the same path as the network file.
from harkpython import harkbasenode

class HarkNode(harkbasenode.HarkBaseNode):
    def __init__(self):
        self.outputNames=("output",)  # one output terminal named "output"
        self.outputTypes=("prim_float",)  # the type is primitive float.

    def calculate(self):
        self.outputValues["output"] = self.input1 ** 3 + self.input2 ** 5
        # set output value
        # from two inputs: input1 and input2.
  1. Run

    batchflow tutorial2.n
    
Then, you will see the following output result
<Float 3152 >

Description

harkbasenode

harkbasenode is a base class for HARK-Python3 that interfaces the python code and HARK processing. To write a code for HARK-Python3, you MUST inherit the harkbasenode class.

For details, in python interpreter, run

from harkpython import harkbasenode
help(harkbasenode)

Support types

Primitives
int, float, complex<float>, string, and ObjectRef (= Source)

Containers | Vector<T> [T = int, float, complex<float>, and Source] | Matrix<T> [T = int, float, complex<float>] | Map<int, T> [T = Vector<int>, Vector<float>, Vector<complex<float> >, Float, Matrix<int>, Matrix<float>, Matrix<complex<float> >]

Container type conversions

Container type of HARK is converted as follows:

HARK type Python type example
Vector numpy.ndarray(1dim) [0.1 0.2 0.3]
Matrix numpy.ndarray(2dim) [[1 2 3][4 5 6][7 8 9]]
Map dict {1: array([1, 2, 3]), 2: array([4, 5, 6])}
Source dict(key=’id’,’x’,’power’) {‘id’: 1, ‘x’: [0.5, 0.5, 0.5], ‘power’: 5.0}
Vector<Source> list [{‘id’: 1, ‘x’: [1., 2., 3.], ‘power’: 5.0}, {‘id’: 2, ‘x’: [4., 5., 6.], ‘power’: 6.0}]

Instance variables

self.nodeName
The name of the node. e.g., node_PyCodeExecutor3_1.
self.nodeID
The ID of the node. If the node name is node_PyCodeExecutor3_1, the ID is 1.
self.count
The number of iterations.

If you want to plot the data for every 100 frames,

if self.count % 100 == 0
    pyplot.plot(data)
    pyplot.pause(0.01)

Parameters of PyCodeExecutor3 and how they are used

DIRECTORY_NAME
This path is added to python path.
MODULENAME
The file name of your code. No extensions.
CLASSNAME
The class name in your code that will be instanciated.

Equivalent code is:

import sys
sys.path.append(DIRECTORY_NAME)
import FILENAME
object = FILENAME.CLASSNAME()

# For each iteration, calculate() is called
object.calculate()

Tips

Can I add a parameter to the script?

Currently, PyCodeExecutor3 does not pass the given parameters to the scripts. Instead, since PyCodeExecutor3 can receive an arbitrary number of inputs, you can realize this using a Constant node.

For example, if you want to add a subnet_param named THRESHOLD to your PyCodeExecutor3,

  1. Add THRESHOLD input to PyCodeExecutor3.
  2. Add Constant node and connect its output to THRESHOLD.
  3. Change the type of the VALUE of the Constant node to subnet_param.

Can I improve the calculation speed?

Some tips exist to improve processing speed.

  1. Use python packages to increase speed: For example, using numpy or scipy will improve the scientific computation including matrix calculation, cython for using C functions, or scipy.weave for embedding C++ code into your python code.

  2. Skip calculation For example, plotting is too heavy to execute at every frame (i.e., 10 msec for default setting). In that case, you can use an instance variable self.count to execute the function at a regular interval.

    Here is an example code:

def calculate(self):
  if not self.count % 100 == 0:
    break

  # do some heavy_calculation

However, if the requirement of calculation speed is really high, you should use HARK-Python only for prototyping, and write the code in C++, which is the standard way in HARK.

I want to see other python code examples

HARK-Python3 includes some examples as described in tutorial 1. You can download HARK-Python3 source code from here.