# cqp/app.cpp

/*******************************************************************************
    Copyright (c) 2022-2023 Qualcomm Technologies, Inc.
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted (subject to the limitations in the disclaimer
    below) provided that the following conditions are met:
    
    * Redistributions of source code must retain the above copyright notice, this
        list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
        this list of conditions and the following disclaimer in the documentation
        and/or other materials provided with the distribution.
    * Neither the name of Qualcomm Technologies, Inc. nor the names of its
        contributors may be used to endorse or promote products derived from this
        software without specific prior written permission.
    
    NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
    THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
    CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
    NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    @brief
    Program to run the FastADAS Convex Quadratic Programming solver.
    *******************************************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <chrono>
    #include <limits>
    #include <cmath>
    #include <cfloat>
    #include <fadas.h>
    #include "../util/util.h"
    
    uint32_t n = 0, m = 0, m_e = 0;
    float64_t precision = 0.0;
    
    /* FIXME remove old
    
    #define UPDATE_QPOASES_VEC_PATH(testVec, prob)   \
    {\
        snprintf( pathG, 256, "%s/%s/G%u_%u_%u.txt", CQP_VEC_PATH, testVec, prob, n, n );\
        snprintf( pathav, 256, "%s/%s/g%u_%u_%u.txt", CQP_VEC_PATH, testVec, prob, n, 1 );\
        snprintf( pathC, 256, "%s/%s/A%u_%u_%u.txt", CQP_VEC_PATH, testVec, prob, m, n );\
        snprintf( pathbv, 256, "%s/%s/b%u_%u_%u.txt", CQP_VEC_PATH, testVec, prob, m, 1 );\
        snprintf( pathxl, 256, "%s/%s/l%u_%u_%u.txt", CQP_VEC_PATH, testVec, prob, n, 1 );\
        snprintf( pathxu, 256, "%s/%s/u%u_%u_%u.txt", CQP_VEC_PATH, testVec, prob, n, 1 );\
        snprintf( pathx_gt, 256, "%s/%s/x_gt%u_%u_%u.txt", CQP_VEC_PATH, testVec, prob, n, 1 );\
    }
    */
    
    #if defined(_WIN32) || defined(_WIN64) || defined(__x86_64__)
        //#define CQP_VEC_PATH           "../../../tst/vectors/CQPOasis"
        #define CQP_VEC_PATH           "../../../tmp/data/BMW_18k"
    #else
        #define CQP_VEC_PATH           "../vectors/CQPS"
    #endif
    
    #define UPDATE_QPOASES_VEC_PATH(testVec, prob)   \
    {\
        snprintf( pathDims, 256, "%s/%s/dims.txt", CQP_VEC_PATH, (testVec) );\
        snprintf( pathG, 256, "%s/%s/G.txt", CQP_VEC_PATH, (testVec) );\
        snprintf( pathav, 256, "%s/%s/p%04u/a.txt", CQP_VEC_PATH, (testVec), (prob) );\
        snprintf( pathC, 256, "%s/%s/C.txt", CQP_VEC_PATH, (testVec) );\
        snprintf( pathbv, 256, "%s/%s/p%04u/bv.txt", CQP_VEC_PATH, (testVec), (prob) );\
        snprintf( pathxl, 256, "%s/%s/p%04u/xl.txt", CQP_VEC_PATH, (testVec), (prob) );\
        snprintf( pathxu, 256, "%s/%s/p%04u/xu.txt", CQP_VEC_PATH, (testVec), (prob) );\
        snprintf( pathx_gt, 256, "%s/%s/p%04u/x_gt.txt", CQP_VEC_PATH, (testVec), (prob) );\
        snprintf( pathobj_gt, 256, "%s/%s/p%04u/obj_gt.txt", CQP_VEC_PATH, (testVec), (prob) );\
    }
    
    float64_t dtime;
    using namespace std::chrono;
    
    // To be updated on consideration of new data
    const uint32_t gTestFolderCount = 4;
    const char* gTestFolders[] = { "chain80w","crane","diesel","CDU"};
    const uint32_t  gTestFoldersize[] = {101, 921, 600, 7201};
    
    void CleanupBuffers(float64_t* G,
                        float64_t* a,
                        float64_t* C,
                        float64_t* bv,
                        float64_t* xl,
                        float64_t* xu,
                        float64_t* xv,
                        float64_t* obj,
                        uint32_t* iter,
                        float64_t* x_gt,
                        float64_t* obj_gt)
    {
        (void)FadasDeregBuf( xv );
        (void)FadasDeregBuf( obj );
        (void)FadasDeregBuf( iter );
        (void)FadasDeregBuf( G );
        (void)FadasDeregBuf( a );
        (void)FadasDeregBuf( C );
        (void)FadasDeregBuf( bv );
        (void)FadasDeregBuf( xl );
        (void)FadasDeregBuf( xu );
    
        (void)FadasMemFree( x_gt );
        (void)FadasMemFree( obj_gt );
        (void)FadasMemFree( xv );
        (void)FadasMemFree( obj );
        (void)FadasMemFree( iter );
        (void)FadasMemFree( G );
        (void)FadasMemFree( a );
        (void)FadasMemFree( C );
        (void)FadasMemFree( bv );
        (void)FadasMemFree( xl );
        (void)FadasMemFree( xu );
    }
    
    bool RunCQP( const char* test_id,
                 const char* dims_data,
                 const char* G_data,
                 const char* av_data,
                 const char* C_data,
                 const char* bv_data,
                 const char* xl_data,
                 const char* xu_data,
                 const char* x_gt_data,
                 const char* obj_gt_data )
    {
        FadasError_e status = FADAS_ERROR_NONE;
        bool ans = true;
        const uint32_t balign = 128;
        uint32_t n = 0, m = 0, m_e = 0;
        size_t memsz;
        float64_t varErrNorm = 0.0;
        float64_t xGtNorm = 0.0;
        float64_t maxErr = 0.0;
        float64_t objErr = 0.0;
        float64_t relObjErr = 0.0;
    
        using std_clock = std::chrono::steady_clock;
    
        uint32_t* dims = (uint32_t*)FadasMemAlloc( (size_t)3 * sizeof( uint32_t ), balign, nullptr );
        if( nullptr == dims )
        {
            UTIL_ERROR( "FadasMemAlloc failed for dims " );
        }
    
        ans = UTIL_ReadUInt( dims_data, 3, dims ); // read problem size
        if( false == ans )
        {
            UTIL_ERROR( "error reading file %s", dims_data );
        }
    
        n = dims[0];
        m = dims[1];
        m_e = dims[2];
    
        UTIL_INFO("n = %u, m = %u, m_e = %u\n", n, m, m_e);
    
        // read matrix G and register buffer
        memsz = ( n * n ) * sizeof( float64_t );
        float64_t* G = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        // read vector a and register buffer
        memsz = n * sizeof( float64_t );
        float64_t* a = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        // read matrix C and register buffer
        memsz = ( n * m ) * sizeof( float64_t );
        float64_t* C = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        // read vector bv and register buffer
        memsz = m * sizeof( float64_t );
        float64_t* bv = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        float64_t* xl;
    
        if( nullptr == xl_data )
        {
            xl = nullptr;
        }
        else
        {
            // read vector xl and register buffer
            memsz = n * sizeof( float64_t );
            xl = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
        }
    
        for (uint32_t i = 0; i < m; ++i)  //TODO:: Wrapper add a minus sign before calling the backend
        {
            bv[i] *= -1;
        }
    
        float64_t* xu;
    
        if( nullptr == xu_data )
        {
            xu = nullptr;
        }
        else
        {
            // read vector xu and register buffer
            memsz = n * sizeof( float64_t );
            xu = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
        }
    
        // register buffer xv
        memsz = n * sizeof( float64_t );
        float64_t* xv = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        // register buffer obj
        memsz = 1 * sizeof( float64_t );
        float64_t* obj = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        // register buffer iter
        memsz = 1 * sizeof( uint32_t );
        uint32_t* iter = (uint32_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        // cond_num
        memsz = 1 * sizeof( float64_t );
        float64_t* cond_num = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        //GT x
        memsz = n * sizeof( float64_t );
        float64_t* x_gt = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        //GT obj
        memsz = 1 * sizeof( float64_t );
        float64_t* obj_gt = (float64_t*)FadasMemAlloc( memsz, balign, nullptr );
    
        if( ( NULL == G ) || ( NULL == a )  ||
            ( NULL == C ) || ( NULL == bv ) ||
            ( NULL == xv ) || ( NULL == obj ) ||
            ( NULL == iter ) || ( NULL == x_gt ) ||
            ( NULL == obj_gt ) || (NULL == cond_num) )
        {
            (void)fprintf( stderr, "Failed to allocate memory\n" );
            // Try and free memory if it is already allocated
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        ans = UTIL_ReadFloat64( G_data, n * n, G );
        if(false == ans)
        {
            UTIL_WARN( "error reading file %s", G_data );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        memsz = ( n * n ) * sizeof( float64_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_IN, (void*)G, size_t( memsz ) );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "Failed to register memory for G [err: %u]", status );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        ans = UTIL_ReadFloat64( av_data, n, a );
        if( false == ans )
        {
            UTIL_WARN( "error reading file %s", av_data );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        memsz = n * sizeof( float64_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_IN, (void*)a, size_t( memsz ) );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "Failed to register memory for a [err: %u]", status );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        ans = UTIL_ReadFloat64( C_data, n * m, C );
        if( false == ans )
        {
            UTIL_WARN( "error reading file %s", C_data );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        memsz = ( n * m ) * sizeof( float64_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_IN, (void*)C, size_t( memsz ) );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "Failed to register memory for C [err: %u]", status );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        ans = UTIL_ReadFloat64( bv_data, m, bv );
        if( false == ans )
        {
            UTIL_WARN( "error reading file %s", bv_data );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        memsz = m * sizeof( float64_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_IN, (void*)bv, size_t( memsz ) );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "Failed to register memory for bv [err: %u]", status );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        if( nullptr != xl_data)
        {
            ans = UTIL_ReadFloat64( xl_data, n, xl );
            if( false == ans )
            {
                UTIL_WARN( "error reading file %s", xl_data );
                CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
                (void) FadasMemFree( dims );
                return false;
            }
    
            memsz = n * sizeof( float64_t );
            status = FadasRegBuf( FADAS_BUF_TYPE_IN, (void*)xl, size_t( memsz ) );
            if( FADAS_ERROR_NONE != status )
            {
                UTIL_WARN( "Failed to register memory for xl [err: %u]", status);
                CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
                (void) FadasMemFree( dims );
                return false;
            }
        }
    
        if( nullptr != xu_data )
        {
            ans = UTIL_ReadFloat64( xu_data, n, xu );
            if( false == ans )
            {
                UTIL_WARN( "error reading file %s", xu_data );
                CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
                (void) FadasMemFree( dims );
                return false;
            }
    
            memsz = n * sizeof( float64_t );
            status = FadasRegBuf( FADAS_BUF_TYPE_IN, (void*)xu, size_t( memsz ) );
            if( FADAS_ERROR_NONE != status )
            {
                UTIL_WARN( "Failed to register memory for xu [err: %u]", status);
                CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
                (void) FadasMemFree( dims );
                return false;
            }
        }
    
        memsz = n * sizeof( float64_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_OUT, (void*)xv, size_t( memsz ) );
        if (FADAS_ERROR_NONE != status)
        {
            UTIL_WARN( "Failed to register memory for xv [err: %u]", status);
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        memsz = 1 * sizeof( float64_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_OUT, (void*)obj, size_t( memsz ) );
        if (FADAS_ERROR_NONE != status)
        {
            UTIL_WARN( "Failed to register memory for obj [err: %u]", status);
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        memsz = 1 * sizeof( uint32_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_OUT, (void*)iter, size_t( memsz ) );
        if (FADAS_ERROR_NONE != status)
        {
            UTIL_WARN( "Failed to register memory for iter [err: %u]", status);
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        memsz = 1 * sizeof( uint32_t );
        status = FadasRegBuf( FADAS_BUF_TYPE_OUT, (void*)cond_num, size_t( memsz ) );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "Failed to register memory for iter [err: %u]", status );
            CleanupBuffers( G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt );
            (void)FadasMemFree( dims );
            return false;
        }
    
        ans = UTIL_ReadFloat64( x_gt_data, n, x_gt );
        if( false == ans )
        {
            UTIL_WARN( "error reading file %s", x_gt_data );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        ans = UTIL_ReadFloat64( obj_gt_data, 1, obj_gt );
        if( false == ans )
        {
            UTIL_WARN( "error reading file %s", obj_gt_data );
            CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
            (void) FadasMemFree( dims );
            return false;
        }
    
        //Both xl and xu should be avaialble or both are null
        bool boundPresent = ( nullptr != xl ) && ( nullptr != xu );
    
        // Create internal buffers
        FadasCQPSolverResult_t qpResults{};
        FadasHandle_t hCQP = nullptr;
        status = FadasCQP_Create( n, m, m_e, 0, nullptr, &hCQP, boundPresent );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "FadasCQP_Create failed! [err: %u]\n", status );
            return false;
        }
    
        qpResults.optimization_result = xv;
        qpResults.obj_result = obj;
        qpResults.required_iterations = iter;
        qpResults.condition_number = *cond_num;
        qpResults.return_status = FADAS_CQP_INIT;
    
        auto t0 = std_clock::now();
        status = FadasCQP_Run( hCQP, G, a, C, bv, xl, xu, 10000, 1e-15, 1e-30, &qpResults );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "FadasCQP_Run failed! [err: %u, qperr: %d]\n",
                           status, qpResults.return_status );
            return false;
        }
    
        auto t1 = std_clock::now();
        long long dt = duration_cast<microseconds>(t1 - t0).count();
        dtime = (double)dt;
    
        if( qpResults.return_status == FADAS_CQP_SUCCESS )
        {
            float64_t err = 0.0;
    
            for( uint32_t i = 0; i < n; i++ )
            {
                err = fabs( qpResults.optimization_result[i] - x_gt[i] );
    
                if(maxErr < err) // compute L_inf norm
                {
                    maxErr = err;
                }
    
                varErrNorm += (err * err);
                xGtNorm += (x_gt[i] * x_gt[i]);
            }
    
            varErrNorm = sqrt(varErrNorm)/( 1.0 + sqrt(xGtNorm));
    
            if (maxErr > 1e-10)
            {
                ans = false;
            }
    
            objErr = fabs( *qpResults.obj_result - *obj_gt );
            relObjErr = objErr / (1.0 + fabs(*obj_gt));
    
            if( objErr > 1e-05 )
            {
                ans = false;
            }
    
            UTIL_INFO("[%s]\nmaxErr = %E, varErrNorm = %E, objErr = %E, relObjErr = %E, solFound = 1, numIters = %u, max_violation = %E, dt = %.2f",
                        test_id, maxErr, varErrNorm, objErr, relObjErr, *qpResults.required_iterations, qpResults.reached_tolerance, dtime);
        }
        else if( qpResults.return_status == FADAS_CQP_SOLUTION_INFEASIBLE )
        {
            UTIL_WARN( "FadasCQP_Run Infeasable Solution!" );
            UTIL_WARN("[%s]\nvarErr = 1.0, objErr = 1.0, solFound = 0, numIters = %u, dt = %.2f",
                       test_id, *qpResults.required_iterations, dtime);
        }
        else if( qpResults.return_status == FADAS_CQP_HESSIAN_NOT_PD )
        {
            UTIL_WARN( "FadasCQP_Run input hessian matrix is not positive definite!" );
        }
        else
        {
            UTIL_WARN( "FadasCQP_Run unknown error!" );
        }
    
        if( false == ans )
        {
            UTIL_WARN( "FadasCQP_Run does not match GT!" );
        }
    
        CleanupBuffers(G, a, C, bv, xl, xu, xv, obj, iter, x_gt, obj_gt);
        (void) FadasMemFree( dims );
    
        status = FadasCQP_Destroy( hCQP );
        if( FADAS_ERROR_NONE != status )
        {
            UTIL_WARN( "FadasCQP_Destroy failed! [err: %u]\n", status );
            ans = false;
        }
    
        return ans;
    }
    
    uint32_t LoadVecAndRun( const char *vec, uint32_t numProbs, uint32_t startFolder = 0 )
    {
        uint32_t n_fails = 0;
        char pathDims[256] = { 0 };
        char pathG[256] = { 0 };
        char pathav[256] = { 0 };
        char pathC[256] = { 0 };
        char pathbv[256] = { 0 };
        char pathxl[256] = { 0 };
        char pathxu[256] = { 0 };
        char pathx_gt[256] = { 0 };
        char pathobj_gt[256] = { 0 };
    
        /* FIXME
        n = numVariables;
        m = numConstraints;
        m_e = numEqualityConstraints;
        precision = precisionVal; */
    
        for(uint32_t p = startFolder; p < numProbs; ++p)
        {
            char testId[64] = {0};
    
            snprintf( testId, 64, "%s_%04u", vec, p); // (p + 1));
    
            UPDATE_QPOASES_VEC_PATH(vec, p);
    
            bool ans = RunCQP( testId, pathDims, pathG, pathav, pathC, pathbv, pathxl, pathxu,
                               pathx_gt, pathobj_gt );
            if( false == ans )
            {
                UTIL_WARN("%s_%04u: failed", vec, p);
                ++n_fails;
            }
            else
            {
                UTIL_INFO("%s_%04u: passed", vec, p);
            }
        }
    
        return n_fails;
    }
    
    int32_t CmdLineHasOption( int32_t argc, char* argv[], const char* optString )
    {
        int32_t position = 0;
    
        for( int32_t i = 1; i < argc; ++i )
        {
            if( !strcmp( argv[i], optString ) )
            {
                position = i;
                break;
            }
        }
    
        return position;
    }
    
    uint32_t FindTestInTestFolders(char * word)
    {
        uint32_t size = gTestFolderCount;
        for (uint32_t i = 0; i < size; ++i)
        {
            if (strcmp(gTestFolders[i], word) == 0)
            {
                return i;
            }
        }
    
        return size;
    }
    
    int32_t main( int32_t argc, char** argv )
    {
        int32_t     retVal      = 0;
        uint32_t    startFolder  = 0;
        uint32_t    endFolder    = 0;
        int32_t     pos         = 0;
        bool        allTest    = false;
        uint32_t posTest = 0;
        if( FADAS_ERROR_NONE != FadasInit( nullptr ) )  // initialize all FADAS features
        {
            UTIL_ERROR( "FadasInit failed\n" );
        }
    
        if( (argc > 7) || CmdLineHasOption( argc, argv, "-h" ) )
        {
            (void)fprintf( stderr, "USAGE: app [-h] [-a]|[-t] [-s] [-e]\n"
                            "  -h = Help information.\n"
                            "  -a = run for all test data\n"
                            "  -t = run for particular test data\n"
                            "       Vectors should be present at path : ../vectors/CQPS\n"
                            "       Available tests: chain80w, crane, diesel, CDU\n"
                            "  -s = Start folder number[0, N), default 0\n"
                            "  -e = End folder number[1, N), default max subfolders present\n"
                    );
            return -1;
        }
    
        //int n_fails_0 = LoadVecAndRun( "chain80w", 101 );
        //int n_fails_1 = LoadVecAndRun( "crane", 921 );
        //int n_fails_2 = LoadVecAndRun( "diesel", 600 );
        //int n_fails_3 = LoadVecAndRun( "CDU", 7201 );
    
        //printf( "STATS:  fails_chain80w = %d / %d = %.2f%%\n", n_fails_0,  101, 100.0 * double( n_fails_0)  / 101.0 );
        //printf( "STATS:  fails_crane = %d / %d = %.2f%%\n", n_fails_1,  921, 100.0 * double( n_fails_1 ) / 921.0 );
        //printf( "STATS:  fails_diesel = %d / %d = %.2f%%\n", n_fails_2,  600, 100.0 * double( n_fails_2 ) / 600.0 );
        //printf( "STATS:  fails_3 = %d / %d = %.2f%%\n", n_fails_3, 7201, 100.0 * double( n_fails_3 ) / 7201.0 );
        pos = CmdLineHasOption( argc, argv, "-a" );
        if ( pos )
        {
            allTest = true;
        }
        else
        {
            pos = CmdLineHasOption( argc, argv, "-t" );
            if ( pos && gTestFolderCount > FindTestInTestFolders(argv[pos+1]) )
            {
                posTest = pos+1;
            }
            else
            {
                (void)fprintf(stderr, "Please provide correct test folder name!\n"
                    "Available tests: chain80w, crane, diesel, CDU\n"
                );
                return -1;
            }
    
            pos = CmdLineHasOption( argc, argv, "-s" );
            if(pos && ((pos+1) < argc))
            {
                (void)sscanf(argv[pos+1], "%u", &startFolder);
            }
    
            pos = CmdLineHasOption( argc, argv, "-e" );
            if(pos && ((pos+1) < argc))
            {
                (void)sscanf(argv[pos+1], "%u", &endFolder);
            }
        }
    
        UTIL_INFO( "cqp sample app is going to run with: \n"
                   "all mode: %d\n"
                   "particular test: %s\n"
                   "start folder: %d\n"
                   "end folder: %d\n\n",
                    allTest, argv[posTest], startFolder, endFolder
        );
    
        // re-arrange endFolder if not given
        uint32_t idx = FindTestInTestFolders(argv[posTest]);
        if(gTestFolderCount > idx)
        {
            if((0 == endFolder) || (gTestFoldersize[idx] < endFolder))
            {
                endFolder = gTestFoldersize[idx];
            }
        }
    
        if(0 == startFolder)
        {
            startFolder = 0;
        }
    
        if(allTest)
        {
            for(uint32_t i=0; i<4; ++i)
            {
                uint32_t n_fails = LoadVecAndRun( gTestFolders[i], gTestFoldersize[i] );
                UTIL_INFO( "STATS:  %s = %d / %d = %.2f%%\n", gTestFolders[i],
                    n_fails,  gTestFoldersize[i], 100.0 * double( n_fails)  / gTestFoldersize[i] );
            }
        }
        else
        {
            if(startFolder >= endFolder)
            {
                (void)fprintf(stderr, "Please provide proper start and end folder numbers!\n");
                return -1;
            }
            uint32_t n_fails = LoadVecAndRun( argv[posTest] , endFolder, startFolder );
            UTIL_INFO( "STATS:  %s = %d / %d = %.2f%%\n", argv[posTest],
                n_fails,  endFolder-startFolder, 100.0 * double( n_fails)  / (endFolder-startFolder) );
        }
    
        if(FADAS_ERROR_NONE != FadasDeInit())
        {
            UTIL_ERROR( "FadasDeInit failed\n" );
        }
    
        return retVal;
    }
    Copy to clipboard

Last Published: Sep 30, 2024

[Previous Topic
cqp\_basic/app.cpp](https://docs.qualcomm.com/bundle/publicresource/80-63309-1/topics/cqp-basic.md) [Next Topic
uyvy/app.cpp](https://docs.qualcomm.com/bundle/publicresource/80-63309-1/topics/uyvy.md)