#!/bin/sh
# autopkgtest check: Build and run a program against libmedc
# (C) 2013 Thomas Moulard
# (C) 2014 Anton Gladky
# Author: Thomas Moulard <thomas.moulard@gmail.com>
#         Anton Gladky <gladk@debian.org>

set -e

WORKDIR=$(mktemp -d)
echo $WORKDIR
trap "rm -rf $WORKDIR" 0 INT QUIT ABRT PIPE TERM
cd $WORKDIR
mkdir src
cd src

cat <<EOF > CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(demo)
find_package(ALGLIB REQUIRED)
include_directories(\${ALGLIB_INCLUDE_DIRS})

add_executable(demo demo.cpp)
target_link_libraries(demo \${ALGLIB_LIB})
install(TARGETS demo DESTINATION bin)

EOF

cat <<EOF > demo.cpp
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "linalg.h"

using namespace alglib;


int main(int argc, char **argv)
{
    //
    // In this example we assume that you already know how to work with
    // rmatrixsyrk() function. Below we concentrate on its multithreading
    // capabilities.
    //
    // SMP edition of ALGLIB includes smp_rmatrixsyrk() - multithreaded
    // version of rmatrixsyrk() function. In the basic edition of ALGLIB
    // (GPL edition or commercial version without SMP support) this function
    // just calls single-threaded stub. So, you may call this function from
    // ANY edition of ALGLIB, but only in SMP edition it will work in really
    // multithreaded mode.
    //
    // In order to use multithreading, you have to:
    // 1) Install SMP edition of ALGLIB.
    // 2) This step is specific for C++ users: you should activate OS-specific
    //    capabilities of ALGLIB by defining AE_OS=AE_POSIX (for *nix systems)
    //    or AE_OS=AE_WINDOWS (for Windows systems).
    //    C# users do not have to perform this step because C# programs are
    //    portable across different systems without OS-specific tuning.
    // 3) Allow ALGLIB to know about number of worker threads to use:
    //    a) autodetection (C++, C#):
    //          ALGLIB will automatically determine number of CPU cores and
    //          (by default) will use all cores except for one. Say, on 4-core
    //          system it will use three cores - unless you manually told it
    //          to use more or less. It will keep your system responsive during
    //          lengthy computations.
    //          Such behavior may be changed with setnworkers() call:
    //          * alglib::setnworkers(0)  = use all cores
    //          * alglib::setnworkers(-1) = leave one core unused
    //          * alglib::setnworkers(-2) = leave two cores unused
    //          * alglib::setnworkers(+2) = use 2 cores (even if you have more)
    //    b) manual specification (C++, C#):
    //          You may want to specify maximum number of worker threads during
    //          compile time by means of preprocessor definition AE_NWORKERS.
    //          For C++ it will be "AE_NWORKERS=X" where X can be any positive number.
    //          For C# it is "AE_NWORKERSX", where X should be replaced by number of
    //          workers (AE_NWORKERS2, AE_NWORKERS3, AE_NWORKERS4, ...).
    //          You can add this definition to compiler command line or change
    //          corresponding project settings in your IDE.
    //
    // After you installed and configured SMP edition of ALGLIB, you may choose
    // between serial and multithreaded versions of SMP-capable functions:
    // * serial version works as usual, in the context of the calling thread
    // * multithreaded version (with "smp_" prefix) creates (or wakes up) worker
    //   threads, inserts task in the worker queue, and waits for completion of
    //   the task. All processing is done in context of worker thread(s).
    //
    // NOTE: because starting/stopping worker threads costs thousands of CPU cycles,
    //       you should not use multithreading for lightweight computational problems.
    //
    // NOTE: some old POSIX-compatible operating systems do not support
    //       sysconf(_SC_NPROCESSORS_ONLN) system call which is required in order
    //       to automatically determine number of active cores. On these systems
    //       you should specify number of cores manually at compile time.
    //       Without it ALGLIB will run in single-threaded mode.
    //
    // Now, back to our example. In this example we will show you:
    // * how to call SMP version of rmatrixsyrk(). Because we work with tiny 2x2
    //   matrices, we won't expect to see ANY speedup from using multithreading.
    //   The only purpose of this demo is to show how to call SMP functions.
    // * how to modify number of worker threads used by ALGLIB
    //
    ae_int_t n = 2;
    ae_int_t k = 1;
    double alpha = 1.0;
    ae_int_t ia = 0;
    ae_int_t ja = 0;
    ae_int_t optypea = 2;
    double beta = 0.0;
    ae_int_t ic = 0;
    ae_int_t jc = 0;
    bool isupper = true;
    real_2d_array a = "[[1,2]]";
    real_2d_array c = "[[]]";

    //
    // Default number of worker threads.
    // Preallocate space to store result, call multithreaded version, test.
    //
    // NOTE: this function updates only one triangular part of C. In our
    //       example we choose to update upper triangle.
    //
    c = "[[0,0],[0,0]]";
    rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[1,2],[0,4]]

    //
    // Override default number of worker threads (set to 2).
    // Preallocate space to store result, call multithreaded version, test.
    //
    // NOTE: this function updates only one triangular part of C. In our
    //       example we choose to update upper triangle.
    //
    alglib::setnworkers(+2);
    c = "[[0,0],[0,0]]";
    rmatrixsyrk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper);
    printf("%s\n", c.tostring(3).c_str()); // EXPECTED: [[1,2],[0,4]]
    return 0;
}


EOF

cd ..
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=./../inst ./../src
make
make install
echo "build: OK"
[ -x demo ]
./demo
echo "run: OK"

