.. _usage:

How to use ezARPACK in your project
===================================

Depending on what build system your C++ project is based on, there are
two ways to use ezARPACK. Either way, you would need

* A compiler supporting C++11 or newer;
* a working `ARPACK-NG installation
  <https://github.com/opencollab/arpack-ng>`_ (version 3.6.0 or newer).
* One of supported :ref:`linear algebra libraries <backends>` (unless
  you are going to :ref:`add support for a new one <new_backend>`).
* A working implementation of MPI-3.0 or newer, such as
  `OpenMPI <https://www.open-mpi.org/>`_ or `MPICH <https://www.mpich.org/>`_,
  if you plan to use the :ref:`Parallel ARPACK solvers <mpi>`.

.. warning::
  The Parallel ARPACK eigensolvers for general complex matrices are
  `known to be unstable <https://github.com/opencollab/arpack-ng/pull/245>`_
  and can yield wrong results in ARPACK-NG versions prior to 3.8.0.
  Be sure to link your code to ARPACK-NG 3.8.0 or newer if you use the
  :ref:`complex <complex>` variant of :cpp:type:`ezarpack::mpi::arpack_solver`.

Makefiles/no build system
-------------------------

Assume that ``<EZARPACK_ROOT>`` is either a directory with unpacked
ezARPACK sources or its :ref:`installation <installation>`
directory. A compiler command line for your program can be as simple as

.. code:: shell

  g++ -O3 -o myprog myprog.cpp \
      -I<EZARPACK_ROOT>/include -L<ARPACK_NG_ROOT>/lib -larpack

  # For executables using the Parallel ARPACK (MPI) solvers
  mpic++ -O3 -o myprog_mpi myprog_mpi.cpp -I<EZARPACK_ROOT>/include \
         -L<ARPACK_NG_ROOT>/lib -larpack -lparpack

(similar for ``clang++`` and other compilers). More ``-I`` flags may be needed
if the linear algebra framework you choose is not visible to the compiler by
default. Similarly, adding ``-I<MPI_ROOT>/include -L<MPI_ROOT>/lib`` may be
necessary if you are using an MPI implementation installed in a non-system
location.

.. note::

  When linking to the static version of ARPACK-NG library
  (``libarpack.a``), you might also need to explicitly link your executable to
  a BLAS/LAPACK implementation. A common symptom of this problem is
  undefined references to ``dgemv_`` and other LAPACK subroutines.

CMake
-----

Here is a minimal example of a root ``CMakeLists.txt`` script for your
project.

.. code:: cmake

  cmake_minimum_required(VERSION 3.13.0 FATAL_ERROR)

  project(myproject LANGUAGES CXX)

  # ezARPACK_ROOT is the installation prefix of ezARPACK.
  set(ezARPACK_DIR ${ezARPACK_ROOT}/lib/cmake)

  # Import ezARPACK target.
  find_package(ezARPACK 1.0 CONFIG REQUIRED)

  # Import Eigen (Blaze, Armadillo, etc) targets.
  find_package(Eigen3 CONFIG REQUIRED)

  # Build an executable called `myprog`.
  add_executable(myprog myprog.cpp)
  target_link_libraries(myprog ezarpack Eigen3::Eigen)

  # Find a usable version of ARPACK-NG.
  find_arpackng(3.6.0 REQUIRED)

  # Link the executable to the ARPACK library.
  target_link_libraries(myprog ${ARPACK_LIBRARIES})

Linking your targets to ARPACK-NG libraries can be a bit of a hassle, as CMake
interface of ARPACK-NG changed a few times since version 3.6.0. In particular,
CMake scripts of the versions prior to 3.8.0 do not export any targets. Instead,
they expose library information via a variable ``arpack_ng_LIBRARIES``.
In order to make linking more user-friendly, ezARPACK exports a macro called
``find_arpackng()``. It finds an ARPACK-NG installation while taking care of
said CMake interface differences. Upon successful detection of ARPACK-NG,
``find_arpackng()`` sets two variables that can be later passed to
``target_link_libraries()``,

  - ``ARPACK_LIBRARIES`` - list of ARPACK libraries and linker flags
  - ``PARPACK_LIBRARIES`` - list of Parallel ARPACK libraries and linker flags

Setting CMake variable ``ARPACK_NG_ROOT`` will instruct ``find_arpackng()``
to look for ARPACK-NG at a specific installation prefix before proceeding
to system locations.

Making the :ref:`Parallel ARPACK solvers <mpi>` work requires additional
linking to MPI and PARPACK.

.. code:: cmake

  # Parallel ARPACK (MPI)

  # Build another executable `myprog_mpi`.
  add_executable(myprog_mpi myprog_mpi.cpp)
  target_link_libraries(myprog_mpi ezarpack Eigen3::Eigen)

  # Detect an MPI-3.0 implementation.
  find_package(MPI 3.0 REQUIRED)

  # Link the executable to the Parallel ARPACK library and to the MPI.
  target_include_directories(myprog_mpi PRIVATE ${MPI_CXX_INCLUDE_PATH})
  target_link_libraries(myprog_mpi ${PARPACK_LIBRARIES} ${MPI_CXX_LIBRARIES})