# Automated Driver Testing for Small Footprint Embedded Systems
††thanks: This work was partially funded by Fundação de Amparo à Pesquisa do
Estado do Rio de Janeiro (Faperj) and Conselho Nacional de Desenvolvimento
Científico e Tecnológico (CNPq).

Sara C. M. Souza  Innovation Hub
Instituto Federal Fluminense, Brazil
ORCID: 0000-0002-0905-8650  Rogerio Atem de Carvalho  Innovation Hub
Instituto Federal Fluminense, Brazil
ORCID: 0000-0003-4429-2482

##  I Introduction

Embedded systems are present on many applications such as in automotive,
aerospace, industrial, and medical applications. These systems drive a
billionaire market and they are responsible for more than 90% of the
processors produced in the world [1].

Embedded System are a combination of hardware and software designed for a
specific purpose, with multiple software layers. Drivers are part of a low
level software layer intended to interact directly to hardware. For example,
the internal peripherals like Timer Modules, SPI Modules and so on. So, there
is a strong interaction between the drivers and internal or external
peripherals and this interaction often makes the embedded software
development, functionality evaluation, system performance measurement, and
automated testing a hard task[2]. This happens because testing demands control
over the inputs and outputs, in this case the hardware, this task is
especially complex for embedded systems given that the physical environment
may not be deterministic and difficult to be recreated during the tests [1].
For example, in order to test a driver which is responsible to produce a PWM
output signal it may be necessary a device in the other side that is able to
capture this signal and verify the frequency of this signal, or to test a
driver that is responsible to get a GPS data it may be necessary to provide a
device that answer a predefined GPS data requests and uses the same physical
communication protocol.

Although in many cases a developer may use real external peripherals to
evaluate his/her driver, in other cases the hardware may not be available
during the software development because it is also in development or because
of its high price [2]. Moreover, the hardware presence may not be wished in
some situations because of the risks it may represent [3]. To understand how
the testing task is relevant and costly, a worldwide research [4] indicated
that 40% of the assigned resources on a project are applied in software
testing activities and can reach up to 80% on critical systems.

In order to address the problems previously described, and taking into account
that a great deal of embedded systems, especially IoT devices, are based on
microcontrollers or SoCs, this paper introduces a low cost solution to test
drivers on this type of computing element. The solution is built upon a method
that employs three components: a Device Under Test (DUT), a Double device, and
a personal computer. The computer runs the test code, i.e., the code that will
compare the expected result with the obtained result, while the DUT runs the
test’s target code, i.e., the driver that the developer wishes to test, and
the Double plays the role of the ”real” external peripherals that communicates
with the DUT, is this device that the driver is supposed to control or
communicate with.

The history of this solution begins with the control software for one of the
payloads of the Brazilian nanosatellite 14-BISat. The development of this
instrument ran in parallel with the development of its control software, which
was carried out by the authors, who used basic Test Driven Development
techniques and a test harness called THC [5, 6]. These initial experiments
generated the Valves 1.0 toolset, which in turn was used to certify the
embedded software in 14-BISat, as described in [7, 8, 9]. From this and other
accumulated experiences and developments, different requirements were
collected in order to improve the process of testing embedded systems, among
which, the creation of hardware and software Doubles, which gave rise to the
solution here presented.

In order to briefly present a solution matured over the years to test the
drivers from small footprint embedded devices, this article is divided into
the following sections:

  * -

The proposed solution section, which presents the system architecture and the
method in detail;

  * -

The test cases section, that describes driver tests performed using up to five
different communication protocols;

  * -

Conclusions, which list the main achievements of the solution, as well as its
shortcomings and current directions.

##  II Proposed Solution

Here is introduced a testing solution for drivers on microcontrollers that,
besides the Device Under Test (DUT), has a a Double device, and a computer, as
well as software associated to each of these components. Their structure and
interactions are described as follows.

###  II-A System Architecture

The hardware elements are represented in Fig. 1. As can be seen in Fig. 2,
System Architecture, each hardware element hosts a software element. The
hardware devices are described as follows:

  1. 1.

Computer: This device hosts the test code and it is responsible for
orchestrating the test by sending commands to the DUT and to the Double, and
for receiving the results of these commands from both;

  2. 2.

Device Under Test: This device is a microcontroller or SoC whose driver is
being tested or evaluated. This device hosts the test’s target code, which is
called the production code;

  3. 3.

Double Device: A Double device is a device that plays the role of an external
peripheral, in the same way that a double plays the role of a real actor on a
movie. The Double provides inputs to the device under test and receives
outputs from it, making the doubled devices transparent from the DUT’s
viewpoint. It supports multiple protocols in order to allow the testing of
different drivers. The Double device hosts the so called Double Code.

Figure 1: Hardware elements.

The software elements are:

  1. 1.

Test Code: it is a Python code running in the computer. It orchestrates the
test by communicating to each device through the injection of commands, and
gathering results from a serial connection. Once the outcomes are gathered,
this code compares the gathered results against the expected results and gives
feedback to the developer. A test code may have one or more test cases. Each
test case aims at testing a small and isolated feature, such as a read/write
operation. According to the Test Driven Development (TDD) philosophy, this
code should be interactively written before the production code;

  2. 2.

Double Code: This code is embedded into the Double device and simulates the
behavior of the real devices. A Double code usually declares a class that
represents an external peripheral, this way the developer may instantiate one
or more testing objects, such as leds from the Led Class, for example. The
solution here presented already supplies some functional Doubles, however, the
development community and the peripheral manufacturers can produce their own
Double Code, supplying extra doubles as necessary;

  3. 3.

Production Code: The code hosted by the DUT that is the target of the tests.
It implements the drivers. This code may be any embedded code.

Figure 2: System Architecture.

###  II-B Materials and Methods

Currently, the Materials used for testing are:

  * •

Two DevKit v1 Evaluation Board (one being the DUT and the other being the
Double). This board host the ESP32, a System On a Chip (SoC) that was chosen
because of its many protocols, the BLE and WiFi feature and because it is very
accessible.

  * •

One laptop running Ubuntu 18.04 Linux Distro.

Regarding the Method, it is centered in what is called a complete test
execution, which is divided into two phases:

  * •

Setup phase: This phase is responsible for establishing a connection, cleaning
up the DUT’s and Double’s file systems, and uploading the proper codes to each
device.

  * •

Execution phase: It is responsible for running all test cases, when each test
case should evaluate a single functionality.

Fig. 3 represents the execution flow of a generic test case. These steps are
described as follows:

  1. 1.

Initialization: the Test Code initializes the production code in the DUT and
the Double Code in the Double device. This is achieved through the
instantiation and initialization of objects on each device using the serial
communication previously established. This step is responsible, for example,
for instantiating a simulated object on the Double device and for indicating
which pins it should use.

  2. 2.

Input Injection: the Test Code places the production code at a state in which
the developer wants to test, also placing the Double Code at a suitable state
corresponding to that test case. A suitable state in this case means a
favorable state for the test case considered, e.g., making the Double
sensitive to external stimulus or making it produce an output. This state is
based upon the real behavior of the given peripheral.

  3. 3.

Results Gathering: the Test Code requests the results from the DUT or the
Double Device.

  4. 4.

Asserts: the Test Code compares the results with the set-point. The outcome of
this assertion is printed out, indicating the result of the test case itself.
This phase uses a Python Module called `should dsl` [10] that allows the use
of specific matchers. Matchers are more than just basic asserts, they allow
more sophisticated comparisons, such as specifying a range of tolerance,
asserting if, for example, a test is successful if a timer expiration value is
between 1999ms and 2001ms.

Figure 3: Execution flow of a unique test case.

For standardization purposes, it was established that Test Codes’ names should
initialize with `"test_"`, production codes with `"dut_"` and Double Codes
with `"Double_"`, followed by an expressive name indicating the main goal of
the code.

##  III Cases

This section presents and discuss the currently implemented cases. Each
subsection aims at exemplifying how to apply the method to test a specific
driver that uses a specific internal peripheral and protocol. For example, the
first subsection presents the Blink Led case, describing how to test the
driver responsible for blinking a led, using the microcontroller’s General
Purpose Input/Output (GPIO) as the internal peripheral. Each subsection
presents the following topics:

  1. 1.

A brief description of the test cases.

  2. 2.

A representative test case snippet.

  3. 3.

The test result.

  4. 4.

The electrical connection between the DUT and the Double.

###  III-A The Blink Led case

  1. 1.

Brief Description: when a developer starts programming in a language, it’s
common to start with the classic ”Hello World” printing code. In the
microcontroller’s environment, the blink led code is often used as the first
exercise in embedded systems studies, as well as to check the basic
functioning of a new evaluation board. Therefore, the classic Blink Led was
used to test GPIO and also as an introduction to the proposed solution’s
method.

  2. 2.

Test Cases: The `"test_blink_led.py"`, which is the test code, has the
following test cases: The `"test_blink_blocking"` and the `"test_blink_isr"`.
The former is intended to test a blink code operating in the blocking mode,
i.e., consuming CPU’s cycles, and the latter is intended to test a blink code
that uses a timer interrupt service routine to blink the led. The
`"test_blink_blocking"` case is exposed in Code 1. The beginning of this code
is composed by constants that describe, respectively, in which pin the led
will be connected to the DUT, in which pin the Double will pretend to be the
led, i.e., the pin the Double will receive the stimulus, how long will the
blinking period last and how many times it will blink. The First part is the
object initialization, with the test initially creating the Led object in the
Double, and then sending the command in the string format via the serial
connection previously established. The command indicates to the Double which
pin it will listen to, and after how many times it can stop and return to the
test the average blink time. Then the test creates the Blinker object in the
DUT, specifying a pin to blink, a blinking period, and the number of blinks.
It’s important to emphasize that the test code had already sent the class file
to these devices before the instantiating process. Also, the Blinker object
contains the driver itself which is the test’s target. The second part is the
input injection, which in this case consisted of calling a Led’s method to
start the signal acquisition and of calling a Blinker’s method to finally
blink the led. In the third part, the test sleeps, in order to wait the led to
blink, and after this interval, the test asks the Double for the blink average
time, which is, in that case, the result. The fourth part is the assertion.
Here, it’s interesting to observe that it was used the `"close_to"` matcher,
which gives the developer the possibility of giving the test a tolerance. In
this example, the maximum absolute error was of 1 millisecond. It means that
the test passes if the time period is 1 millisecond more or less. The last
part was simply the decommissioning, i.e., memory cleaning. The
`"test_blink_isr"` is pretty similar to this case, with the difference in the
called method on DUT, in which a timer interrupt service routine is
configured.

Code 1: Test case: test_blink_ blocking()

⬇

led_pin_dut = ”2”

led_pin_double = ”21”

period_blink = ”1000”

blinking_times = ”2”

…

# 1 - Objects Creation

self.double_serial.repl(”red_led␣=

Led(”+led_pin_double+”,

”+blinking_times+”)”,0.1)

self.dut_serial.repl(”blinker␣=

Blinker(”+led_pin_dut+”,”+period_blink+”,

”+blinking_times+”)”,0.1)

# 2 - Input Injection

self.double_serial.repl(

”red_led.start_acquisition()”,0.1)

self.dut_serial.repl(

”blinker.blink_blocking()”,0.1)

# 3 - Results gathering

sleep(…) #To give the test enough time

obtained_period = self.double_serial.repl(

”red_led.get_average_period()”,0.2)[2]

…

# 4 - Assertion

obtained_period |should| close_to

(period_blink, delta = 1)

# 5 - decommissioning

self.dut_serial.repl(”del␣blinker”,0.1)

self.double_serial.repl(”del␣red_led”,0.1)

  1. 3.

Results: Fig. 4 presents the result of the Blink Led test, gives detailed
feedback about each test case and provides the input test parameters and the
output.

Figure 4: The blink test result.

  1. 4.

The electrical connection: Fig. 5 presents the electrical connection for
testing the blink led. There are two wires, one for the led’s fake connection
and one for the ground.

Figure 5: The blink test electrical connection.

###  III-B The RTC case

  1. 1.

Brief Description: An external Real-Time Clock (RTC) is often used to keep the
Date and Time information even when the device is turned off. The RTC of this
example uses an I2C interface to communicate with the microcontroller. The
basic expected functions of an RTC’s driver are setting and getting the Date
and Time from the RTC. Therefore, this test aimed at separately testing each
of these functionalities. The isolated test for these functionalities deserves
special attention because this approach allows the `get` method to be tested
even when the `set` method is not implemented. To do so, the Double plays the
role of an RTC model DS3231.

  2. 2.

Test Cases: This test set contains four test cases. The
`test_set_date_time_static` is intended to test the set method, the static
suffix is used because in this case the Double keeps the Date and Time instead
of start counting from that Date and Time onward. However, the
`test_set_date_time_dynamic` is also intended to test the set method, in this
case, the Double operates in the dynamic mode, i.e., it creates fake registers
where the Date and Time information is stored and it uses its internal timer
to update these registers. This mode brings a more realistic behavior and
allows a dynamic testing experience. This case is exposed in Code 2. The
`test_get_date_time` is simply intended to test the get method. And the case
`test_set_get_date_time` is intended to test a full operation: a set call
followed by a get call. This last case was specially designed to accomplish an
autotest, i.e., the DUT injects the input through the get method and gathers
the result through the set method, and verifies the functioning of its own
external peripheral before operating.

Code 2: Test case: test_set_date_time_dynamic()

⬇

# datatime format: [Year, month, day,

# weekday, hour, minute, second]

expected_datetime =[2019,10,23,4,10,51,32]

my_delay = 2

# 1 - Objects Creation

self.double_serial.repl(

”ds3231␣=␣DOUBLE_DS3231(21,22)”,0.2)

self.dut_serial.repl(

”rtc_conf␣=␣ConfTime(21,22)”,0.2)

# 2 - Input Injection

self.dut_serial.repl(

”rtc_conf.set_date_time(

”+str(expected_datetime)+”)”, 0.4)

self.double_serial.repl(

”ds3231.use_internal_rtc()”, 0.2)

sleep(my_delay)

expected_datetime[6] += my_delay

# 3 - Results gathering

gotten_datetime = self.double_serial.

repl(”ds3231.DateTime()”,0.2)[2]

# 4 - Assertion

…

gotten_datetime |should| equal_to

(str(expected_datetime))

  1. 3.

Results: Fig. 6 presents the result of the Conf Time test, giving detailed
feedback about each test case, providing the input test parameters and the
output.

Figure 6: The conf time result.

  1. 4.

The electrical connection: Fig. 7 presents the electrical connection for the
RTC’s testing, having three wires, two for the I2C connection and one for the
ground. There are also two pull-up resistors.

Figure 7: The conf time test electrical connection.

###  III-C The GPS case

  1. 1.

Brief Description: An external Global Positioning System (GPS) is often used
to get geographic coordinates, date, time, and other information. The GPS
module of this example uses a UART interface to communicate with the
microcontroller. The Double was based on the model NEO-6M, a very popular
module in the microcontrollers’ arena. A microcontroller configures the GPS
module and receives the information from it through National Marine
Electronics Association (NMEA) sentences. NMEA sentences hold specific codes
and a format to identify the configuration or the information [11]. Although
the major part of GPS libraries are composed of parser and handler methods
used to interpret these NMEA sentences, the test here presented focuses only
on sending commands and the reception of related information, given that this
is the part of the library that interacts with the hardware.

  2. 2.

Test Cases: This test contains three test cases. The
`test_send_command_configuration` is intended to test the `send_command`
method, which is responsible for configuring the module by sending a NMEA
sentence that indicates the kind of information the microcontroller wants to
receive. The `test_send_command_update_rate` also sends a command, but this
time the command indicates to the GPS module the update rate in which it
should send the information. When the Double receives such a command, it
enables a timer to periodically send a preconfigured NMEA sentence, e.g., a
static sentence that contains a latitude and longitude value. This possibility
is especially useful when a developer is creating the driver in an environment
in which satellite signals are weak or there are other connection problems -
in special laboratories where signal interference is quite common. This case
is exposed in the Code 3. The `test_get_latitude` is intended to test the
multiple library layers, from the driver up to the parser and handler. For
this purpose the `get_latitude` method is tested and it includes the UART
reading and the interpretation of the received sentence.

Code 3: Test case: test_send_command_update_rate().

⬇

command = ’PMTK220,1000’

expected_answer = ’$GPRMC,

141623.523,A,2143.963,S,04111.493,

W,,,301019,000.0,W*7B\n’

# 1 - Objects Creation

self.double_serial.repl(

”gps␣=␣DOUBLE_GPS(22,16,2)”,0.2)

self.dut_serial.repl(

”tracker␣=␣Positioning(17,16,2)”,0.2)

# 2 - Input Injection

self.dut_serial.repl(

”tracker.send_command(’”+command+”’)”,0.2)

self.double_serial.repl(

”gps.received_command()”,0.2)

sleep(1)

# 3 - Results gathering

gotten_answer = self.dut_serial.repl(

”tracker.received_command()”,0.2)[2]

# 4 - Assertion

…

gotten_answer |should| equal_to

(expected_answer)

  1. 3.

Results: Fig. 8 presents the result of the Positioning GPS test, giving
detailed feedback about each test case, providing the input test parameters
and the corresponding output.

Figure 8: The positioning GPS test result.

  1. 4.

The electrical connection: Fig. 9 presents the electrical connection for the
UART testing, having three wires, two for the TX and RX lines, and one for the
ground.

Figure 9: The Positioning GPS test electrical connection.

###  III-D The SPI case

  1. 1.

Brief Description: This example shows how to test the operation of sending and
receiving data on the SPI bus. The DOUBLE is playing the role of a generic SPI
slave as any peripheral that uses SPI to talk to a microcontroller. After
stress testing, meaning repeatedly executing this driver’s tests, the test
revealed an instability of the SPI protocol when operating in the slave mode,
i.e., the Double’s SPI. Thus, although the test target was the DUT, which
works in the master mode, the test results exposed an instability of SPI
working in slave mode. Instability here means that sometimes the test passed
and other times the test failed, unpredictably.

  2. 2.

Test Cases: The test cases basically consisted on sending and receiving data
to the DUT. To test the send operation, the data received by the Double was
compared with the data sent by the master (DUT). To test the receive
operation, the data sent by the Double was compared to the data received by
the DUT. To exemplify with one test case, Code 4 exposes a case that was
intended to perform a read operation without indicating a register address,
i.e., only retrieving the available data in the RX buffer, exactly like the
read operations in ADCs.

Code 4: Test case: test_reading_registers_without_indicating_address().

⬇

expected_written = [1,2,3]

gotten_values = []

# 1 - Objects Creation

self.double_serial.repl

(”slave␣=␣Double_slave(13,12,14,15)”,0.2)

self.dut_serial.repl

(”master␣=␣Dut_master(13,12,14,15)”,0.2)

# 2 - Input Injection

self.double_serial.repl

(”slave.enable_transaction([0,0,0])”,0.2)

self.dut_serial.repl

(”master.write_registers_wo_address

(”+str(expected_written)+”)”,0.2)

# 3 - Results gathering

gotten_values = self.double_serial.repl

(”slave.get_received_buffer()”, 0.2)[2]

gotten_values = gotten_values.decode()

# 4 - Assertion

gotten_values |should| equal_to

(str(expected_written))

  1. 3.

Results: Fig. 10 presents the result of a successful SPI test while Fig. 11
presents a failed execution.

Figure 10: A successfull SPI test result.

Figure 11: A failed SPI test result.

  1. 4.

The electrical connection: Fig. 12 presents the electrical connection for the
SPI testing, having five wires: four for the SPI communication (SCLK, MISO,
MOSI and CS) buses, and one for the ground.

Figure 12: The SPI test electrical connection.

###  III-E The BLE case

  1. 1.

Brief Description: The Bluetooth Low Energy is a wireless communication
protocol introduced by the Bluetooth 4.0 specification. It’s often used in
MCU, sensors, smart watches and IoT devices to communicate to other more
robust devices such as smartphones and laptops. The BLE specification uses the
Generic Access Profile (GAP) and Generic Attribute Profile (GATT) standards.
Together, these standards specifies roles played by the devices, how they
discover each other, how they establish a connection, and how they change
information. According to the GAP specification, before establishing a
connection, a Peripheral device starts advertising its offered services,
address, and other informations. Thus, a Central device will be able to scan
these information and initialize a connection. Small devices, like IoT
devices, often operates in the Peripheral mode, while robust devices, like
smartphones, often operates in the Central mode [12]. In this test, the DUT is
operating in the Peripheral mode, playing the role of a generic Temperature
Sensor and the goal was to test the code that allows a connection and reads
and notifies the temperature over Bluetooth. To accomplish it, the Double
operated in the Central mode and played the role of a smartphone.

  2. 2.

Test Cases: This test set contains three test cases. The `test_connection`
intended to test the connectivity between the sensor and the smartphone. The
`test_read` and `test_notify` intended to test a read operation initiated by
the smartphone and the notification promoted by the sensor. To exemplify with
one test case, Code 5 exposes the connection test case.

Code 5: Test case: test_connection().

⬇

advertising_name = ”my_sensor”

# 1 - Objects Creation and Input Injection

self.dut_serial.repl(”sensor␣=␣BLE_Sensor

(\””+advertising_name+”\”)”, 0.2)

self.double_serial.repl(”cellphone␣=

DOUBLE_cellphone()”, 0.2)

time.sleep(5)

# 3 - Result Gathering

connection = self.double_serial.repl

(”cellphone.check_connectivity()”, 0.2)[2]

connection = connection.decode()

connection |should| contain (str(True))

  1. 3.

Results: Fig. 13 presents the result of a successful BLE test while Fig. 14
presents a failed execution in debug mode, where it’s possible to see the
commands being executed in both devices. The test result was unstable given
that in some executions the time for BLE initialization was so long that the
test was executed before the Double had the chance to finish initializing and
establishing a connection. It’s possible to realize in Fig. 14 that the
cellphone was not de-initialized because the Double terminal was blocked still
waiting to initialize the BLE. The interesting point is that after we had this
result, we searched for the problem and we could find an issue in GitHub
regarding it [13]. So, once more, the framework showed up effective to reveal
driver’s implementation problems.

Figure 13: A successfull BLE test result.

Figure 14: A failed BLE test result.

##  IV Conclusions

This paper introduced a solution that deliveries a practical and efficient way
of testing drivers in Small Footprint Embedded Systems. The solution is
composed by multiple artifacts, including libraries, templates, and test
cases, all functional in the given protocols. Among the five protocols here
presented, Bluetooth Low Energy (BLE) and Serial Peripheral Interface (SPI)
have shown instability, due to the recent libraries’ development for the
target platform. However, an interesting result obtained during the
development of the solution was that the tests created for these protocols
were capable of exposing these instabilities, which were then reported to the
corresponding development communities. All the artifacts, along with clear
instructions are published in GitHub at [14], as a invitation to
collaborators.

The target platform and language of choice, ESP32 and Micropython, were chosen
due to the protocol diversity of this SoC and the possibility of accessing an
interactive terminal that allows running the tests and reading their results,
respectively. It is important to note that the Double can be used with other
platforms, given that it implemented in a transparent way - exactly to act as
a double.

Also, it must be observed that the method is noninvasive, which means that
there is no need for changing the production code or loading code into the
target hardware in order to going under testing. There’s no breakpoints and no
necessity for setting a special debug mode for running the tests. However, in
practice, the Test Code’s execution may add some delays when sending commands
and receiving results through the serial port, reinforcing the need for good
test design.

Therefore, our contribution is threefold: studying the extension of the
concept of Doubles from software to hardware, supplying a functional hardware
and software solution for testing drivers in Small Footprint Embedded Systems,
and pinpointing errors in two of driver implementations for the developer
community. Current work is divided into exploring other protocols and
providing test-case automated code generation.

## References

  * [1] A. Banerjee, S. Chattopadhyay, and A. Roychoudhury, “On testing embedded software,” in _Advances in Computers_. Elsevier, 2016, vol. 101, pp. 121–153.
  * [2] J. W. Grenning, _Test Driven Development for Embedded C_. Pragmatic bookshelf, 2011.
  * [3] G. Ellis, _Control system design guide: using your computer to understand and diagnose feedback controllers_. Butterworth-Heinemann, 2012.
  * [4] A. M. R. Vincenzi, M. E. Delamaro, A. C. Dias Neto, S. C. P. F. Fabbri, M. Jino, and J. C. Maldonado, _Software Testing Automatization with free software tools._ Elsevier (in Portuguese), 2018.
  * [5] R. A. Carvalho, H. S. Ferreira, R. F. Toledo, C. C. S., and G. L. Moura, “Interfacing with the science unit: Preparing the software side.” _Proceedings of the 6th European CubeSat Symposium_ , 2014.
  * [6] R. A. Carvalho, H. Silva, R. F. Toledo, and M. S. de Azevedo, “Tdd for embedded systems: A basic approach and toolset,” _arXiv preprint arXiv:1507.07969_ , 2015.
  * [7] R. A. Carvalho, G. V. S. Arueira, M. S. Azevedo, and R. F. Toledo, “Developing the software for cubesats in a concurrent engineering environment: a toolset and case study.” _Second IAA Latin American CubeSat Workshop IAA Latin American CubeSat Workshop_ , 2016.
  * [8] R. A. Carvalho, M. S. de Azevedo, S. C. de Souza, G. V. Arueira, and C. S. Cordeiro, “Developing and testing software for the 14-bisat nanosatellite,” _IFAC-PapersOnLine_ , vol. 49, no. 30, pp. 71–74, 2016.
  * [9] R. A. Carvalho, G. V. S. Arueira, and S. C. M. Souza, “An environment for developing software for small satellites.” _1st International Academy of Astronautics Latin American Symposium on Small Satellites_ , 2017.
  * [10] H. Tavares, G. G. Rezende, V. Mota, R. S. Manhães, and R. A. de Carvalho, “A tool stack for implementing behaviour-driven development in python language,” _CoRR_ , 2010.
  * [11] G. Baddeley. (2001, Jul) Gps - nmea sentence information. [Online]. Available: http://aprs.gids.nl/nmea/
  * [12] K. Townsend. (2020) Introduction to bluetooth low energy. [Online]. Available: https://learn.adafruit.com/introduction-to-bluetooth-low-energy/introduction
  * [13] Zukial. (2020) Ble on esp32 inconsistent init time (sometimes ¿ 10s). [Online]. Available: https://github.com/micropython/micropython/issues/5489
  * [14] S. da Cunha Monteiro de Souza. (2020, Feb) micropython_test_lib. [Online]. Available: https://github.com/saramonteiro/micropython_test_lib


# Boost-RS: Boosted Embeddings for Recommender Systems and its Application to
Enzyme-Substrate Interaction Prediction

Xinmeng Li, Li-Ping Liu, and Soha Hassoun
Department of Computer Science, Tufts University, Medford 02155, USA

###### Abstract

Motivation: Despite experimental and curation efforts, the extent of enzyme
promiscuity on substrates continues to be largely unexplored and under
documented. Recommender systems (RS), which are currently unexplored for the
enzyme-substrate interaction prediction problem, can be utilized to provide
enzyme recommendations for substrates, and vice versa. The performance of
Collaborative-Filtering (CF) recommender systems however hinges on the quality
of embedding vectors of users and items (enzymes and substrates in our case).
Importantly, enhancing CF embeddings with heterogeneous auxiliary data,
specially relational data (e.g., hierarchical, pairwise, or groupings),
remains a challenge.
Results: We propose an innovative general RS framework, termed Boost-RS, that
enhances RS performance by “boosting” embedding vectors through auxiliary
data. Specifically, Boost-RS is trained and dynamically tuned on multiple
relevant auxiliary learning tasks Boost-RS utilizes contrastive learning tasks
to exploit relational data. To show the efficacy of Boost-RS for the enzyme-
substrate prediction interaction problem, we apply the Boost-RS framework to
several baseline CF models. We show that each of our auxiliary tasks boosts
learning of the embedding vectors, and that contrastive learning using Boost-
RS outperforms attribute concatenation and multi-label learning. We also show
that Boost-RS outperforms similarity-based models. Ablation studies and
visualization of learned representations highlight the importance of using
contrastive learning on some of the auxiliary data in boosting the embedding
vectors.
Availability and implementation: A Python implementation for Boost-RS is
provided at
https://github.com/HassounLab/Boost-RS
Contact<EMAIL_ADDRESS>and<EMAIL_ADDRESS>

##  1 Introduction

Understanding the rich functionality of enzymes is fundamental in advancing
biochemistry, molecular and synthetic biology and many other application
domains. Enzymes were assumed specific, catalyzing a specific substrate;
however, there is now wide consensus that enzymes are promiscuous, catalyzing
many substrates, including substrates that the enzymes did not evolve to
catalyze (Tawfik and S, 2010). Our ability to analyze this inherent
promiscuity has proved instrumental in guiding the direct evolution of novel
proteins (Romero and Arnold, 2009), elucidating metabolism in natural and
engineered organisms (Porokhin et al., 2021), and creating novel synthesis
pathway to produce valuable therapeutics and commodity molecules (Bowie et
al., 2020). Despite progress in protein function annotation and modeling
protein-ligand interactions (mostly focused on drug-ligand interactions), and
manual and automated curation efforts , there remains large gaps in our
knowledge of enzyme capabilities. Computational tools that predict enzyme
promiscuity on molecules can augment existing knowledge, guide biological and
biomedical applications and reduce costly experimental efforts.

Computational approaches for predicting enzyme-substrate interactions target
different applications. Physics-based models, including molecular docking and
molecular dynamic simulations, attempt to identify the most favorable binding
mode of a ligand with a given target protein These methods require 3D models
of both protein and molecule, and require significant compute time, making
these methods suitable for detailed analysis of a small number of
interactions. Rule-based methods predict site of metabolism or products of
enzymatic transformations on a query molecule. Most such methods, however,
utilize hand-curated biotransformation rules (e.g., (Ridder and Wagener,
2008)), or applicable to only specific enzymes (e.g., (Tyzack and Kirchmair,
2019)), thus limiting their general applicability. Machine-Learning (ML)
approaches have taken advantage of available enzymatic data and solve many
important questions such the likelihood of enzymatic transformations between a
compound pair, e.g. Support Vector Machines (Kotera et al., 2013), graph
embedding (Jiang et al., 2021), identifying enzyme commission numbers that act
on molecules, e.g. using hierarchical classification of enzymes on molecules
(Visani et al., 2020), and predicting the likelihood of a sequence catalyzing
a reaction or quantifying the affinity of sequences on substrates using
Gaussian processes (Mellor et al., 2016). Once trained, ML models provide
quick evaluation and are suited for many bioengineering and biological
applications that require the exploration of the vast interaction space.

To expand the use of ML in predicting enzyme-substrate interactions, we
investigate the use of recommender systems to recommend enzymes that are
likely to act on specific substrates, and/or compounds that are suited as
substrates for an enzyme. Recommender systems (RS) are heavily utilized in
industrial applications. For example, more than 50% of all AI training cycles
at Facebook are devoted to training deep learning recommendation models (Acun
et al., 2021). RS, however, were not used prior for predicting enzyme-
substrate interactions. Previously, RS were used for predicting protein-drug
interactions (Bagherian et al., 2021). Many such techniques employ
collaborative filtering (CF) in the form of matrix factorization (MF), e.g.,
Multiple Similarities Collaborative Matrix Factorization (MSCMF) (Zheng et
al., 2013), Probabilistic Matrix Factorization (PMF) (Mnih and Salakhutdinov,
2008), Neighborhood Regularized Logistic Matrix Factorization (NRLMF) (Liu et
al., 2016).

As the performance of CF hinges on learned embeddings of the users and items,
prior RS techniques aimed to utilize auxiliary (side) data to learn improved
embeddings. Many techniques enhance CF by using similarities among proteins
and among drugs, e.g., MSCMF (Zheng et al., 2013) or neighborhood
regularization, e.g., NRLMF (Liu et al., 2016), and REMAP (Lim et al., 2016),
with the goal of minimizing distances between a protein (or a drug) and its
nearest neighbors in the latent space. Other RS aim to integrate auxiliary
data by fusing knowledge graphs (e.g., (Wang et al., 2021)), or integrating
multi-source data (e.g., (Zhu et al., 2017), (Gao et al., 2018)). In practice,
auxiliary data is complex and often exhibits multiple relational aspects: item
labels may be hierarchical, and users may share a group label (zip code,
building address, or profession). The common practice to concatenate auxiliary
data with the learned embedding does not necessarily maximally exploit the
relational aspect of the data. A general methodology for computing enhanced
embeddings based on relational data and other complex heterogeneous auxiliary
data therefore remains a challenge.

We present in this paper a novel technique, Boost-RS, for enhancing the
performance of RS by ”boosting” the embedding vectors through auxiliary
learning tasks. Boost-RS integrates the primary CF task with boosting tasks
that aim to upgrade the embedding vectors based on available heterogeneous
auxiliary data. The integration of user and item attributes addresses the
interaction matrix sparsity issue and has already shown RS performance
improvements (Sun et al., 2019; Bagherian et al., 2021). To minimize negative
transfer from the auxiliary tasks to the main task, the CF and the boosting
tasks are dynamically weighted (Liu et al., 2019). Each auxiliary task is
designed to maximally utilize the available auxiliary data. Importantly, to
learn from relational data, Boost-RS employs contrastive learning, which
contrasts positive and negative samples to learn discriminative
representations in a self-supervised manner. Contrastive learning is applied
through triplet loss (Weinberger and Saul, 2009), where the model is trained
to produce representations such that, for a given anchor example, a positive
example is closer to the anchor than a negative example. Prior RS contrastive
work (Liu et al., 2021) used perturbation to user (or item) preferences and
contrasted the perturbed views to maximize learning mutual information between
the two views.

We demonstrate Boost-RS’s effectiveness by applying it to the enzyme-substrate
interaction prediction problem. The CF primary task of interaction prediction
is accompanied by multi tasks that learn from heterogeneous auxiliary data.
For enzymes, we exploit the Enzyme Commission (EC) hierarchical relationships
and the enzyme functional orthologs. For substrates, we utilize the molecular
fingerprints and substrate-substrate biotransformation relationships due to
functionally similar enzymes. We use contrastive learning on the enzyme
functional orthologs and the biotransformation relationships, and formulate a
hierarchical loss on the EC relationships. Our main contributions are:

  * •

Creating a flexible and generalizable framework, Boost-RS, that enriches the
embedding vectors for CF-based recommender systems using individual and
relational heterogeneous auxiliary data.

  * •

Showing that using contrastive learning on relational data may outperform
other techniques such as multi-labels learning and concatenation with learned
embeddings.

  * •

Demonstrating the generality of the Boost-RS framework by showcasing its
applicability to three recent neural network baseline CFs: Deep Matrix
Factorization (DMF) (Xue et al., 2017), Neural Graph Collaborative Filtering
(NGCF) (Wang et al., 2019), and Neural Matrix Factorization (NMF) (He et al.,
2017).

  * •

Showing that Boost-RS outperforms state-of-the-art similarity-based Graph
Regularized Generalized Matrix Factorization (GRGMF) recommender systems
(Zhang et al., 2020).

##  2 Methods

###  2.1 Dataset

Figure 1: Boost-RS framework for enzyme-substrate recommendation prediction.
A) Interaction matrix construction from enzymatic reactions. e.g., for $E1$,
three positive interactions are added to the matrix. B) The Boost-RS framework
that integrates the main task of interaction prediction with related auxiliary
tasks. C) Collaborative filtering models used as baselines.

We apply Boost-RS to the enzyme-substrate interaction prediction task to
recommend substrates to enzymes that are most likely to interact and vice
versa. Our dataset is culled from biochemical reactions in the KEGG database
(Kanehisa and Goto, 2000). As most biochemical reactions are reversible, no
distinction is made between substrates and products, and hence interacting
molecules are referred to as compounds or substrates interchangeably.
Reactions form a bipartite graph that can be captured as a binary interaction
matrix between enzymes and substrates (Fig. 1A), where each row represents a
compound, and each column represents an enzyme. A matrix entry is set to $1$
if the compound and enzyme participate the same reaction, therefore
representing a positive interaction instance. An entry is set to $0$ in case
there is no catalogued enzyme-substrate interaction. Compounds that are common
to many enzymatic reactions, including cofactors such as ATP and NADH and
metals, are excluded from the matrix. To ensure valid data splits, enzymes or
compounds with a single entry in the interaction matrix are also excluded. In
total, 17,627 enzyme-compound interactions are collected. They involve 4,768
enzymes and 6,397 compounds. The interaction matrix is therefore sparse with
0.06% positive entries.

###  2.2 Auxiliary Data

Four attributes are collected or derived from the KEGG database and are used
for training auxiliary tasks:

Enzyme Commission (EC) numbers. Each enzyme is associated with an EC number
(Webb et al., 1992) that comprises four numbers, separated by dots, starting
with a number that broadly represents the enzyme class, then the sub-class,
sub-subclass, and a final number that reflects the specificity of the enzyme
towards a small group of substrates. As the EC numbers are hierarchical, the
auxiliary learning task of EC prediction can be formulated as such. The EC
numbers have 7, 94, and 164 distinct labels in the first three respective
fields of EC. We only consider the first three fields of EC, as the fourth
index typically denotes specific substrates and cofactors.

Functional Orthologs (KO) numbers. Another enzyme attribute is its KEGG
functional orthology (KO) number (Kanehisa et al., 2016). A particular KO
designation, the letter K followed by 5 numerical digits, is assigned to a
group of genes sharing similar functionality. KO numbers can therefore be
considered as a ”group” attribute. We utilize 5575 sets of KO designations.

Molecular fingerprints (FP).  Based on descriptions for molecules in the KEGG
database, molecular attributes in the form of MACCS fingerprints (FP) (Durant
et al., 2002) are calculated using RDKIT.

Compound-compound biotransformations (CC). The KEGG database provides
biotransformation patterns, designated as RClasses, shared by multiple
substrate-product, or compound-compound (CC), pairs. CC pairs under the same
RClass are transformed by enzymes with similar functionality (e.g.,
hydroxylation or methylation). CC relationships give rise to a compound-
centric graph, akin to a social network. This graph is not a similarity
network as CC pairs are not necessarily similar: a compound may undergo
significant molecular changes under some enzymatic transformations (e.g.,
transferases, ligases).

###  2.3 The Boost-RS model

####  2.3.1 Main task: interaction prediction

The main task of the Boost-RS framework (Fig. 1B) is “recommending” compounds
to enzymes (or enzymes to compound). Per the interaction matrix, an entry
$y_{ij}$ is $1$ for the positive interaction set, $P$, and $y_{ij}$ is $0$ for
the negative interaction set, $N$. As in a standard recommendation task, the
main task function, $f_{main}(\cdot,\cdot)$, predicts the probability
$\hat{y}_{ij}$ of interaction using learned enzyme and compound
representations. We denote the representations for compound $i$ and enzyme $j$
as $\mathbf{v}_{i}$ and $\mathbf{u}_{j}$, respectively. The probability of
interaction, $\hat{y}_{ij}$, and task loss, $\mathcal{L}_{main}$, are then
defined as:

$\displaystyle\hat{y}_{ij}=f_{main}(\mathbf{v}_{i},\mathbf{u}_{j})$ (1)
$\displaystyle\mathcal{L}_{main}=\sum_{i,j}BCE(\hat{y}_{ij},y_{ij})$ (2)

In the simplest form,
$f_{main}(\mathbf{v}_{i},\mathbf{u}_{j})=\mathbf{v}_{i}^{\top}\mathbf{u}_{j}$.
In more complex forms, $f_{main}(\mathbf{v}_{i},\mathbf{u}_{j})$ is calculated
using neural networks. The parameters for $f_{main}$ and the representations
of enzymes and compounds are updated by minimizing the task loss. The
specifics of this loss are dependent on the underlying base CF model used as a
RS (see Section 2.3.4). The embedding vectors, $\mathbf{v}_{i}$ and
$\mathbf{u}_{j}$, are critically important for the recommendation task. To
boost performance, we inject task-relevant auxiliary data for compounds and
enzymes into the embedding vectors via multi-task learning.

####  2.3.2 Auxiliary tasks

Each auxiliary task calculates attribute probabilities with an auxiliary task
function and updates representations and parameters based on the task loss. To
address the differing characteristic in relational attributes, auxiliary
losses are defined on individual, hierarchical, group, and pairwise
attributes. While we describe the details relevant to the specific substrate
and enzyme attributes, the framework easily accommodates other attributes with
individual and relational attributes.

Using FP as an individual attribute, we denote the function for FP prediction
as $f_{FP}$. As each compound fingerprint is a binary vector, we use BCE to
evaluate the prediction accuracy for each vector entry. The FP prediction
function and the FP task loss are defined as:

$\displaystyle\hat{y}^{FP}_{i}=f_{FP}\left(\mathbf{v}_{i}\right),$ (3)
$\displaystyle\mathcal{L}_{FP}=\frac{1}{|C|}*\frac{1}{l_{FP}}\sum_{i\in
C}BCE(\hat{y}_{i}^{FP},y_{i}^{FP}),$ (4)

where $C$ is the set of compounds, and $l_{FP}$ is the length of the
fingerprint vector.

For EC prediction, we capitalize on the EC’s hierarchical structure, and
denote the function for EC prediction as $f_{EC}$. The loss for each enzyme is
based on the cross entropy loss on each of its field set, $FS_{1}$, $FS_{2}$,
$FS_{3}$ for the first, the first two, and the first three fields of the EC
number, respectively. The prediction function and the cumulative task loss for
the EC attribute is therefore:

$\displaystyle\hat{y}^{EC}_{j,FS_{k}}=f_{EC}\left(\mathbf{u}_{j}\right),$ (5)
$\displaystyle\mathcal{L}_{EC}=\frac{1}{|E|}\sum_{j\in
E}\sum_{k=1}^{3}w_{k}\cdot CE(\hat{y}^{EC}_{j,FS_{k}},y^{EC}_{j,FS_{k}}),$ (6)

where $E$ is the set of enzymes, and $k$ is indicating which field set, $FS$,
in EC are we calculating the cross entropy loss on its distinct labels. And
$w_{k}$ is the weight for the $FS_{k}$ field set in EC, and, after some
tuning, is set to $\frac{1}{3}$, therefore equalizing each field’s
contribution to the loss.

When using group attributes and pairwise relationship for the auxiliary tasks,
we denote functions for KO prediction and CC prediction as $f_{KO}$ and
$f_{CC}$, respectively. We utilize triplet loss, with the intention of pulling
the representation of samples in the same set closer together in the embedding
space and pushing away the representation of a sample outside the set. A
function, $d(\cdot)$, measures the distance between a pair of representations.
The CC loss function is defined as:

$\displaystyle\mathcal{L}_{CC}=\frac{1}{|C|}\sum_{i,P_{i},N_{i}\in
C}\max(0,d\left(\mathbf{v}_{i},\mathbf{v}_{P_{i}}\right)-d\left(\mathbf{v}_{i},\mathbf{v}_{N_{i}}\right)+\gamma),$
(7)

where $i$ an anchor compound, $P_{i}$ is a compound in the set of compounds
has CC pairwise relationship with compound $i$, $N_{i}$ is a compound in a set
of compounds that does not have an CC relationship with compound $i$, and
$\gamma$ is a positive margin between the positive $P_{i}$ and negative
$N_{i}$ samples.

The KO loss function is defined similarly to the CC loss function, except that
the anchor, positive and negative samples are derived from the KO group
relationships defined on the enzymes. The contrastive loss on CC reflect a
pairwise relationship within the compound-centric relational graph, while the
loss on KO reflects the group label distinction.

####  2.3.3 Dynamic training

The Boost-RS loss, $\mathcal{L_{\text{Boost-RS}}}$, is the weighted sum of
losses of the main task and auxiliary tasks:

$\displaystyle\mathcal{L_{\text{Boost-
RS}}}=\alpha_{main}\,\mathcal{L}_{main}+\alpha_{aux}\,\mathcal{L}_{aux},$ (8)

where $L_{aux}$ is the additive losses across the auxiliary tasks,
$\alpha_{main}$ and $\alpha_{aux}$ are weights for the main task and auxiliary
tasks, respectively.

The weights of task losses directly influence the performance of interaction
prediction. We employ a dynamic strategy to balance the weights among the main
task and auxiliary tasks. The abridged linear schedule (Belharbi et al., 2016)
emphasizes auxiliary tasks in the early training epochs and shifts the focus
to the main task in later epochs. We assign weights for the main and auxiliary
tasks losses as follows:

$\displaystyle\alpha_{main}=\min(\frac{t}{T},1);\alpha_{aux}=\max(1-\alpha_{main},0),$
(9)

where $t$ is the current training iteration, and $T$ is time point where the
focus shifts completely to the main task.

####  2.3.4 Deep-learning baseline recommender systems

We use three neural-network recommender systems (Fig. 1C) for the interaction
prediction task: DMF (Xue et al., 2017), NGCF (Wang et al., 2019), and NMF (He
et al., 2017). Each recommender system has its own characteristic and may be
better suited for some applications. We apply Boost-RS to each of these
models.

The inputs to DMF are the rows and columns of the interaction matrix. Two
separate Multi-layer Perceptron (MLP) networks are trained through $f_{main}$
to learn compound and enzyme representations. The similarity of the enzyme and
compound representations are computed using cosine similarity and outputed as
the probability of the interaction, $\hat{y}$. Normalized cross entropy loss
is used to compute the loss between $y$ and $\hat{y}$.

To compute $f_{main}$, NGCF first applies graph neural network to the
bipartite interaction graph. Graph Neural Network (GNN) are utilized to learn
node representations. GNNs can account for different order neighbors including
first order neighbors, second order neighbors, and so on. Node representations
for enzyme (compound) nodes that are learned for each level of neighbors are
then concatenated. The inner product of the enzyme and compound
representations is then computed. To compute the loss, an additional
optimization step (not shown in the figure) favors assigning higher
predictions for known interactions than for unknown interactions.

For NMF, $f_{main}$ has GMF and MLP working in parallel and are then followed
with a scoring layer. GMF and MLP each learn independent representations. A
function $\sigma$ calculates the interaction probability based on the
concatenation of the learned representations.

##  3 Results

###  3.1 Experimental setup

We divide positive interactions into training, validation, and test sets at a
ratio of 7:2:1. During training and validation, negative interactions are
randomly sampled from the unknown interactions at a negative sampling ratio,
which is a hyperparameter that varies across models. During testing, all
unknown interactions are assumed negative. Positive interactions in the
training set are excluded during sampling.

As the test data set is imbalanced, where the ratio of positive to the assumed
negative interactions is less than 0.01%, evaluation metrics are selected to
reflect the ability of RS to rank positive interactions ahead of negative
ones. Average Precision (AP) computes the average precision after each
predicted positive interaction in the ranked order list provided by RS. AP is
utilized for model selection. To place lower emphasis on the exact ranking of
known interactions, R-Precision computes the precision after all R positive
interactions have been identified in the ranked order list. The overall
performance at distinguishing between positive and negative interactions is
reported using the area under the receiver operating characteristic curve
(AUC). We additionally report the Mean AP (MAP) and the R-Precision across the
enzymes and the substrates. As each enzyme and substrate had a varied number
of positives, we also report the MAP for the top 3 items (MAP@3) and the
precision on the top one item (Precision@1).

For the three baseline recommender systems, we follow the authors’ guidelines
on hyperparameter tuning. The range of hyperparameter search is specified as
follows. The negative sampling ratio for training set is selected from
$\\{1,5,10,15,20,25,30\\}$. The margin in the triplet loss, $\gamma$, is
selected from $\\{0.5,1.0,1.5\\}$. The dimension of the two hidden layers of
MLPs of $f_{main}(\cdot),f_{FP}(\cdot),f_{EC}(\cdot)$ predictor is selected
from {128, 256, 512}. We optimize our models with the Adam optimizer (Kingma
and Ba, 2015) with learning rates selected among
$\\{10^{-1},10^{-2},10^{-3},10^{-4}\\}$. We apply dropout at a rate selected
from $\\{0.0,0.3,0.5\\}$ and L2 norm at a weight selected from
$\\{10^{-2},10^{-3},\ldots,10^{-6}\\}$. For the abridged linear dynamic
weighting strategy, we allow a maximum of 3000 iterations, with $T=2000$.
During the first 2000 iterations, the model shifts linearly from training the
auxiliary tasks to the interaction prediction task. Training is stopped early
if there is no improved MAP on the validation set in 500 consecutive
iterations.

Table 1: Interaction-prediction performance evaluation. The best model (Boost-RS) is based on NMF and utilizes contrastive learning on KO and CC, hierarchical learning on EC, and individual attribute learning on FP.  | Overall | Enzymes | Compounds
---|---|---|---
| AP | R-Precision | AUC | MAP | R-Precision | MAP@3 | Precision@1 | MAP | R-Precision | MAP@3 | Precision@1
| A. Baselines and their boosted models
DMF | 0.154 | 0.344 | 0.869 | 0.328 | 0.251 | 0.261 | 0.255 | 0.281 | 0.282 | 0.334 | 0.332
Boost-DMF | 0.192 | 0.401 | 0.954 | 0.374 | 0.258 | 0.273 | 0.294 | 0.309 | 0.296 | 0.362 | 0.374
NGCF | 0.169 | 0.328 | 0.810 | 0.333 | 0.274 | 0.278 | 0.261 | 0.277 | 0.297 | 0.347 | 0.326
Boost-NGCF | 0.223 | 0.503 | 0.959 | 0.552 | 0.295 | 0.446 | 0.393 | 0.405 | 0.488 | 0.566 | 0.490
NMF | 0.280 | 0.380 | 0.880 | 0.339 | 0.322 | 0.286 | 0.309 | 0.332 | 0.320 | 0.362 | 0.378
Boost-RS (Boost-NMF) | 0.488 | 0.638 | 0.968 | 0.595 | 0.510 | 0.506 | 0.545 | 0.568 | 0.546 | 0.620 | 0.637
| B. Group data treated as individual attributes and incorporated into RS via
either multi-tasking or concatenation
Boost-RS_Multi-label | 0.404 | 0.492 | 0.936 | 0.419 | 0.411 | 0.353 | 0.421 | 0.452 | 0.395 | 0.441 | 0.490
NMF-Concat_Multi-label | 0.396 | 0.485 | 0.950 | 0.430 | 0.406 | 0.363 | 0.413 | 0.441 | 0.408 | 0.454 | 0.480
| C. Interaction prediction with each auxiliary task using Boost-RS
Boost-RS(KO) | 0.296 | 0.377 | 0.857 | 0.321 | 0.315 | 0.280 | 0.321 | 0.349 | 0.319 | 0.347 | 0.381
Boost-RS(FP) | 0.309 | 0.402 | 0.914 | 0.370 | 0.333 | 0.307 | 0.327 | 0.350 | 0.340 | 0.388 | 0.395
Boost-RS(EC) | 0.344 | 0.432 | 0.880 | 0.337 | 0.377 | 0.294 | 0.372 | 0.399 | 0.325 | 0.364 | 0.438
Boost-RS(CC) | 0.419 | 0.548 | 0.936 | 0.527 | 0.447 | 0.447 | 0.467 | 0.492 | 0.487 | 0.553 | 0.546
| D. Interaction prediction with each auxiliary data using NMF-Concat_Multi-
label
NMF-Concat(KO) | 0.285 | 0.386 | 0.872 | 0.346 | 0.327 | 0.296 | 0.319 | 0.343 | 0.337 | 0.375 | 0.384
NMF-Concat(FP) | 0.287 | 0.386 | 0.870 | 0.338 | 0.329 | 0.286 | 0.318 | 0.344 | 0.324 | 0.368 | 0.386
NMF-Concat(EC) | 0.292 | 0.390 | 0.879 | 0.339 | 0.333 | 0.289 | 0.324 | 0.349 | 0.320 | 0.361 | 0.392
NMF-Concat(CC) | 0.322 | 0.408 | 0.868 | 0.351 | 0.343 | 0.297 | 0.351 | 0.372 | 0.342 | 0.380 | 0.412
| E. Interaction prediction comparing Boost-RS framework against similarity-
based method
GRGMF(FP+EC) | 0.189 | 0.407 | 0.946 | 0.362 | 0.282 | 0.266 | 0.293 | 0.307 | 0.281 | 0.361 | 0.387
Boost-RS(FP+EC) | 0.349 | 0.456 | 0.931 | 0.376 | 0.377 | 0.314 | 0.385 | 0.408 | 0.352 | 0.398 | 0.453

###  3.2 Evaluating Boost-RS on baseline models

We evaluate the performance gain (Table 1A) when implementing Boost-RS for the
three baselines Boost-RS significantly boosts the performance of every
baseline across all metrics. NMF, which is the best performing baseline, gains
74%, 68%, and 10% on MAP, R-Precision, and AUC, respectively, when combined
with Boost-RS. For this work, we use Boost-NMF as our ”Boost-RS” model, and
use NMF as a baseline model for the rest of the experiments, unless noted
otherwise. Boost-RS utilizes contrastive learning on KO and CC, hierarchical
learning on EC, and individual attribute learning on FP.

###  3.3 Multi-label learning via multi-tasking or concatenation

We create a compound (enzyme) binary multi-label vector for CC (KO), where
each entry of the vector indicates the presence or absence of an RClass (KO)
designation. The length of the vector is the number of distinct CCs (KOs). For
CC, the multi-label vector has 3163 entries, where each compound is involved
on average with 1.03 distinct CCs. For KO, the multi-label vector has a length
of 5575 entries, where each enzyme has on average 1.37 distinct KO
designations.

We then compare multi-label performance using contrastive loss (Boost-
RS_Multi-label), where we use weighted BCE for the multi-label loss, and using
concatenation (NMF-Concat_Multi-label), where we concatenate the outputs of
GMF and MLP with the outputs of MLP layers representing the auxiliary data.
The comparisons (Table 1B) utilize multi-label KO and CC data along with
hierarchical EC and FP attributes. Boost-RS_Multi-label outperforms NMF-
Concat_Multi-label as contrastive learning explicitly enforces negative pairs
to have distinct representations, while multi-label training does not.
Further, the sparsity of the KO and CC multi-label vectors (less than 0.1% of
non-zero vector entries) may contribute to the limited improvements using
concatenation. Importantly, a flexible framework such as Boost-RS allows the
judicious selection of the appropriate losses to boost the embeddings (last
row of Table 1A).

We use t-SNE (Van der Maaten and Hinton, 2008) to visualize learned enzyme and
compound representations (Fig. 2) using the various techniques (NMF, NMF-
Concat_Multi-label, Boost-RS_Multi-label, and Boost-RS). Enzyme
representations are shown to the left of each sub-panel. Compound
representations are shown to the right of each sub-panel, where an edge is
added between two compound representations if the two compounds are related
via a CC. For the enzyme representations, each dot is colored with an EC
class. Enzymes in sub-panels C and D form the most distinguishable clusters
when compared to sub-panels A and B as both multi-label and contrastive
learning perform well on KO (see next section). Across the sub-panels,
compound representations initially show no evident pattern (sub-panel A), but
display more defined clusters with the progression towards sub-panel D. There
is a node grouping on the left side of the D sub-panel for compounds that lack
a CC relation as evident by the absence of any edges connecting these
compounds.

Figure 2: Visualization using t-SNE for learned representation of enzymes and
compounds, shown to the left and right of each sub-panel, respectively. A)
Baseline NMF. B) Baseline with multi-label KO and CC concatenation (NMF-
Concat_Multi-label). C) Boost-RS with the auxiliary task of learning multi-
label KO and CC (Boost-RS_Multi-label). D) Boost-RS with triplet loss on KO
and CC (Boost-RS).

###  3.4 Contributions of individual auxiliary tasks

We characterize the contribution of each auxiliary task to the performance of
Boost-RS independently of other tasks (Table 1C). We also contrast each such
contribution against using the same data via concatenation with the baseline
NMF model (Table 1D). For both Boost-RS and NMF-Concat, each auxiliary task
contributes positively to predicting the overall interactions, indicating that
these auxiliary tasks are relevant to the main task and provide additional
information beyond what is captured within CF. For Boost-RS, CC contributes
the most (50% improvement on the overall AP), while while KO, FP, and EC show
more modest improvements (6%, 10%, 23% respectively). For NMF-Concat, CC
improves the baseline NMF by 15% AP, while KO, FP and EC show limited
improvements (2%, 3%, 4%, respectively). Boost-RS(CC) improves enzyme and
compound MAPs significantly (enzyme MAP by 55% and compound MAP by 48%). These
results indicate that each auxiliary data improves the learning of compound
and enzyme representations.

Boost-RS consistently improves performance on each tasks over NMF-concat, with
the exception of the KO prediction task on select metrics other than overall
AP, Precision1 for enzymes, and MAP for the compounds. Despite this
performance variation and other experimental evaluations, learning KO using
contrastive learning results in the best boosting performance (last row in
Table 1A) as our model selection is based on AP. We attribute this varied
performance to the characteristics of the KO auxiliary data. For KO,
contrastive loss is applied on 779 paired relationships, where there are
multiple pairwise relationships involving all pairs of enzymes under the same
KO group label. In contrast, for CC, contrastive loss is applied to 7915
paired relationships derived from pairwise compound-compound transformations.

###  3.5 Boost-RS vs similarity-based models

We compare Boost-RS with a recent recommender system, Graph Regularized
Generalized Matrix Factorization (GRGMF) (Zhang et al., 2020). In addition to
implementing matrix factorization, GRGMF learns latent node representations
based on their neighborhood similarity. GRGMF therefore provides an
alternative model for incorporating EC and FP auxiliary data. GRGMF takes as
input a pairwise compound-similarity matrix and a pairwise enzyme-similarity
matrix, where we use EC numbers and FP to obtain Jaccard similarity scores. CC
and KO relationships cannot be readily integrated with GRGMF. We therefore
evaluate Boost-RS when using only EC and FP as auxiliary data. Boost-RS
outperforms GRGMF in most metrics, except for the AUC of GRGMF (Table 1E). The
results show that the Boost-RS framework can effectively capture the auxiliary
data.

##  4 Conclusion

Our proposed framework, Boost-RS, offers an elegant and generalizable model
for boosting learned representations with heterogeneous auxiliary data for CF
recommender systems. Dynamically training Boost-RS on multiple tasks allows
evolving their relative weights along the learning epochs. The learning tasks
are applicable to various individual and relational attributes. While intended
as a general framework, we here demonstrated the utility of Boost-RS for
enzyme-substrate interaction prediction task. We demonstrated Boost-RS on
three CF baseline models. We identified four auxiliary data (molecular
fingerprints, enzyme commission numbers, functional orthologs and
biotransformation relationships), and proved their relevance for enhancing
interaction prediction. Importantly, we showed the flexibility of Boost-RS
framework through multi-task learning allows the integration of various
auxiliary data modalities such as individual attributes, group attributes,
pairwise relationship. Replacing relational attributes with their multi-label
representations and using them concatenation or multi-task learning, cannot
achieve the same performance boost as with Boost-RS. We compared Boost-RS with
similarity-based RS models and showed that Boost-RS outperforms GRGMF when
utilizing the same data. Because of its demonstrated advantages, generality
and elegance in integrating attributes with CF, the Boost-RS framework may
prove beneficial for a diverse set of application. Further, the use of the
trained auxiliary machinery might prove useful in addressing the cold-start
problem, common across recommender systems.

## Acknowledgements

## Funding

This research is supported by NSF Award 1909536. Li-Ping Liu is supported by
NSF Award 1850358 and NSF Award 1908617. The research is also supported by the
NIGMS of the National Institutes of Health, Award R01GM132391. The content is
solely the responsibility of the authors and does not necessarily represent
the official views of the NIH.

## References

  * Acun et al. [2021] Acun, B., Murphy, M., Wang, X., Nie, J., Wu, C.-J., and Hazelwood, K. (2021).  Understanding training efficiency of deep learning recommendation models at scale.  In 2021 IEEE International Symposium on High-Performance Computer Architecture (HPCA), pages 802–814. IEEE.
  * Bagherian et al. [2021] Bagherian, M., Sabeti, E., Wang, K., Sartor, M. A., Nikolovska-Coleska, Z., and Najarian, K. (2021).  Machine learning approaches and databases for prediction of drug–target interaction: a survey paper.  Briefings in bioinformatics, 22(1), 247–269.
  * Belharbi et al. [2016] Belharbi, S., Hérault, R., Chatelain, C., and Adam, S. (2016).  Deep multi-task learning with evolving weights.  In ESANN.
  * Bowie et al. [2020] Bowie, J. U., Sherkhanov, S., Korman, T. P., Valliere, M. A., Opgenorth, P. H., and Liu, H. (2020).  Synthetic biochemistry: the bio-inspired cell-free approach to commodity chemical production.  Trends in biotechnology, 38(7), 766–778.
  * Durant et al. [2002] Durant, J. L., Leland, B. A., Henry, D. R., and Nourse, J. G. (2002).  Reoptimization of mdl keys for use in drug discovery.  Journal of chemical information and computer sciences, 42(6), 1273–1280.
  * Gao et al. [2018] Gao, L., Yang, H., Wu, J., Zhou, C., Lu, W., and Hu, Y. (2018).  Recommendation with multi-source heterogeneous information.  In IJCAI International Joint Conference on Artificial Intelligence.
  * He et al. [2017] He, X., Liao, L., Zhang, H., Nie, L., Hu, X., and Chua, T.-S. (2017).  Neural collaborative filtering.  In Proceedings of the 26th international conference on world wide web, pages 173–182.
  * Jiang et al. [2021] Jiang, J., Liu, L.-P., and Hassoun, S. (2021).  Learning graph representations of biochemical networks and its application to enzymatic link prediction.  Bioinformatics, 37(6), 793–799.
  * Kanehisa and Goto [2000] Kanehisa, M. and Goto, S. (2000).  Kegg: kyoto encyclopedia of genes and genomes.  Nucleic acids research, 28(1), 27–30.
  * Kanehisa et al. [2016] Kanehisa, M., Sato, Y., Kawashima, M., Furumichi, M., and Tanabe, M. (2016).  Kegg as a reference resource for gene and protein annotation.  Nucleic acids research, 44(D1), D457–D462.
  * Kingma and Ba [2015] Kingma, D. P. and Ba, J. (2015).  Adam: A method for stochastic optimization.  ICLR.
  * Kotera et al. [2013] Kotera, M., Tabei, Y., Yamanishi, Y., Moriya, Y., Tokimatsu, T., Kanehisa, M., and Goto, S. (2013).  Kcf-s: Kegg chemical function and substructure for improved interpretability and prediction in chemical bioinformatics.  BMC systems biology, 7(6), 1–17.
  * Lim et al. [2016] Lim, H., Poleksic, A., Yao, Y., Tong, H., He, D., Zhuang, L., Meng, P., and Xie, L. (2016).  Large-scale off-target identification using fast and accurate dual regularized one-class collaborative filtering and its application to drug repurposing.  PLoS computational biology, 12(10), e1005135.
  * Liu et al. [2019] Liu, S., Liang, Y., and Gitter, A. (2019).  Loss-balanced task weighting to reduce negative transfer in multi-task learning.  In Proceedings of the AAAI Conference on Artificial Intelligence, volume 33, pages 9977–9978.
  * Liu et al. [2016] Liu, Y., Wu, M., Miao, C., Zhao, P., and Li, X.-L. (2016).  Neighborhood regularized logistic matrix factorization for drug-target interaction prediction.  PLoS computational biology, 12(2), e1004760.
  * Liu et al. [2021] Liu, Z., Ma, Y., Ouyang, Y., and Xiong, Z. (2021).  Contrastive learning for recommender system.  arXiv preprint arXiv:2101.01317.
  * Mellor et al. [2016] Mellor, J., Grigoras, I., Carbonell, P., and Faulon, J.-L. (2016).  Semisupervised gaussian process for automated enzyme search.  ACS synthetic biology, 5(6), 518–528.
  * Mnih and Salakhutdinov [2008] Mnih, A. and Salakhutdinov, R. R. (2008).  Probabilistic matrix factorization.  In Advances in neural information processing systems, pages 1257–1264.
  * Porokhin et al. [2021] Porokhin, V., Amin, S. A., Nicks, T. B., Gopinarayanan, V. E., Nair, N. U., and Hassoun, S. (2021).  Analysis of metabolic network disruption in engineered microbial hosts due to enzyme promiscuity.  Metabolic Engineering Communications, 12, e00170.
  * Ridder and Wagener [2008] Ridder, L. and Wagener, M. (2008).  Sygma: combining expert knowledge and empirical scoring in the prediction of metabolites.  ChemMedChem: Chemistry Enabling Drug Discovery, 3(5), 821–832.
  * Romero and Arnold [2009] Romero, P. A. and Arnold, F. H. (2009).  Exploring protein fitness landscapes by directed evolution.  Nature reviews Molecular cell biology, 10(12), 866–876.
  * Sun et al. [2019] Sun, Z., Guo, Q., Yang, J., Fang, H., Guo, G., Zhang, J., and Burke, R. (2019).  Research commentary on recommendations with side information: A survey and research directions.  Electronic Commerce Research and Applications, 37, 100879\.
  * Tawfik and S [2010] Tawfik, O. K. and S, D. (2010).  Enzyme promiscuity: a mechanistic and evolutionary perspective.  Annual review of biochemistry, 79, 471–505.
  * Tyzack and Kirchmair [2019] Tyzack, J. D. and Kirchmair, J. (2019).  Computational methods and tools to predict cytochrome p450 metabolism for drug discovery.  Chemical biology & drug design, 93(4), 377–386.
  * Van der Maaten and Hinton [2008] Van der Maaten, L. and Hinton, G. (2008).  Visualizing data using t-sne.  Journal of machine learning research, 9(11).
  * Visani et al. [2020] Visani, G. M., Hughes, M. C., and Hassoun, S. (2020).  Enzyme promiscuity prediction using hierarchy-informed multi-label classification.  arXiv preprint arXiv:2002.07327.
  * Wang et al. [2019] Wang, X., He, X., Wang, M., Feng, F., and Chua, T.-S. (2019).  Neural graph collaborative filtering.  In Proceedings of the 42nd international ACM SIGIR conference on Research and development in Information Retrieval, pages 165–174.
  * Wang et al. [2021] Wang, Y., Dong, L., Li, Y., and Zhang, H. (2021).  Multitask feature learning approach for knowledge graph enhanced recommendations with ripplenet.  Plos one, 16(5), e0251162.
  * Webb et al. [1992] Webb, E. C. et al. (1992).  Enzyme nomenclature 1992. Recommendations of the Nomenclature Committee of the International Union of Biochemistry and Molecular Biology on the Nomenclature and Classification of Enzymes. Number Ed. 6 in 6. Academic Press.
  * Weinberger and Saul [2009] Weinberger, K. Q. and Saul, L. K. (2009).  Distance metric learning for large margin nearest neighbor classification.  Journal of machine learning research, 10(2).
  * Xue et al. [2017] Xue, H.-J., Dai, X., Zhang, J., Huang, S., and Chen, J. (2017).  Deep matrix factorization models for recommender systems.  In IJCAI, volume 17, pages 3203–3209. Melbourne, Australia.
  * Zhang et al. [2020] Zhang, Z.-C., Zhang, X.-F., Wu, M., Ou-Yang, L., Zhao, X.-M., and Li, X.-L. (2020).  A graph regularized generalized matrix factorization model for predicting links in biomedical bipartite networks.  Bioinformatics, 36(11), 3474–3481.
  * Zheng et al. [2013] Zheng, X., Ding, H., Mamitsuka, H., and Zhu, S. (2013).  Collaborative matrix factorization with multiple similarities for predicting drug-target interactions.  In Proceedings of the 19th ACM SIGKDD international conference on Knowledge discovery and data mining, pages 1025–1033.
  * Zhu et al. [2017] Zhu, J., Zhang, J., He, L., Wu, Q., Zhou, B., Zhang, C., and Yu, P. S. (2017).  Broad learning based multi-source collaborative recommendation.  In Proceedings of the 2017 ACM on Conference on Information and Knowledge Management, pages 1409–1418.