Adding a command to RevKit
This tutorial explains how to integrate a new simple command into RevKit. As an example, a command called unopt is implemented, that copies gate in a reversible circuit without modifying the functionality.
CirKit provides utility scripts in order to create new files easily. We create a file for the new command using the following script:
./utils/make_src_file.py reversible/cli/commands/unopt reversible
Note, that the first argument is the path to the filename without the src/ in the beginning and without an extension in the end. Two files, a header and a source file, are created. The second parameter ensures that the files are created for the RevKit add-on. The third parameter is optional and can have a name of the file author. If not specified, the name is fetched from the user's git configuration.
The header file in addons/cirkit-addon-reversible/src/reversible/cli/commands/unopt.hpp contains already some skeleton code and we extend it as follows (all comments are omitted in the code):
// unopt.hpp
#ifndef CLI_UNOPT_COMMAND_HPP
#define CLI_UNOPT_COMMAND_HPP
#include <core/cli/cirkit_command.hpp>
namespace cirkit
{
class unopt_command : public cirkit_command
{
public:
unopt_command( const environment::ptr& env );
rules_t validity_rules() const;
protected:
bool execute();
private:
unsigned copies = 1u;
};
}
#endif
We define a command with the base class
cirkit_command
.
It is important that the class name is
unopt_command
to be used in later code that makes use of macros and relies on some naming conventions.
Two methods need to be implemented, the constructor that will set up the arguments which can be passed to the command, and
execute
which executes the code and calls our algorithm.
We also implement the method
validity_rules
to ensure that the store contains at least one reversible circuit when calling the command.
More details on how to write commands can be found in the
abc_cli
example program.
Next we implement both these methods in the source file:
// unopt.cpp
#include "unopt.hpp"
#include <alice/rules.hpp>
#include <core/utils/program_options.hpp>
#include <reversible/target_tags.hpp>
#include <reversible/cli/stores.hpp>
#include <reversible/functions/copy_metadata.hpp>
namespace cirkit
{
unopt_command::unopt_command( const environment::ptr& env )
: cirkit_command( env, "unoptimize circuits" )
{
opts.add_options()
( "copies,c", value_with_default( &copies ), "number of gate copies" )
;
add_new_option(); /* adds a flag --new, or -n that can be used to add a new
store entry instead of overwriting it */
}
command::rules_t unopt_command::validity_rules() const
{
return {has_store_element<circuit>( env )};
}
bool unopt_command::execute()
{
auto& circuits = env->store<circuit>(); /* access store with reversible circuits */
/* reference to current circuit, and new circuit with same properties */
const auto& circ = circuits.current();
circuit circ_new;
copy_metadata( circ, circ_new );
for ( const auto& g : circ ) /* iterate through the gates */
{
circ_new.append_gate() = g; /* copy existing gate */
if ( is_toffoli( g ) ) /* some more copies, if gate is Toffoli */
{
for ( auto i = 0u; i < 2u * copies; ++i )
{
circ_new.append_gate() = g;
}
}
}
extend_if_new( circuits ); /* extend store by empty element if --new option is set */
circuits.current() = circ_new;
return true; /* always return true */
}
}
The function should always return true
.
We are almost done. Next, we add the command to the RevKit executable. For this purpose, open the file addons/cirkit-addon-reversible/programs/reversible/revkit.cpp and add the following header, where other headers are included:
#include <reversible/cli/commands/unopt.hpp>
And then add the command in the same style as other commands are added using:
ADD_COMMAND( unopt );
That's it. We rebuild RevKit with
make -C build revkit
and then call it to try out the new command:
revkit> read_spec -p "0 4 2 1 0 3 7 5"
revkit> tbs
[i] run-time: 0.00 secs
revkit> ps -c
Lines: 3
Gates: 7
T-count: 21
Logic qubits: 4
revkit> unopt
revkit> ps -c
Lines: 3
Gates: 21
T-count: 63
Logic qubits: 4
Exercises
Here are some suggestions for exercises (with a difficulty estimation from 0–50) to extend the add-on.
- [25] Copy all gates which are self-inverse in this manner based on a syntactic comparison.