Project: s41467-024-46596-y | Function: fold (cpp)

system: You are an expert C++ programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow C++ best practices and maintain consistent code style.
Return **only** the complete C++ function code.

user: Complete this C++ function:

**DESCRIPTION:** Calculates minimum free energy RNA secondary structure using dynamic programming algorithm for napRNA structure prediction

**KEY TERMS:** {
  "c": "energy array for i-j pairs",
  "fML": "multi-loop auxiliary energy array",
  "f5": "energy of 5' end",
  "DMLi": "minimum energy for multiloop regions",
  "ptype": "precomputed pair types",
  "ggg": "G-quadruplex energies"
}

**CONTEXT CODE:** /** \file **/

/*
                  minimum free energy
                  RNA secondary structure prediction

                  c Ivo Hofacker, Chrisoph Flamm
                  original implementation by
                  Walter Fontana
                  g-quadruplex support and threadsafety
                  by Ronny Lorenz

                  Vienna RNA package
*/

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>

#include "utils.h"
#include "energy_par.h"
#include "fold_vars.h"
#include "pair_mat.h"
#include "params.h"
#include "loop_energies.h"
#include "data_structures.h"
#include "gquad.h"
#include "fold.h"

#ifdef _OPENMP
#include <omp.h>
#endif


#define PAREN
#define STACK_BULGE1      1       /* stacking energies for bulges of size 1 */
#define NEW_NINIO         1       /* new asymetry penalty */
#define MAXSECTORS        500     /* dimension for a backtrack array */
#define LOCALITY          0.      /* locality parameter for base-pairs */

#define SAME_STRAND(I,J)  (((I)>=cut_point)||((J)<cut_point))

/*
#################################
# GLOBAL VARIABLES              #
#################################
*/
PUBLIC  int logML     = 0;  /* if nonzero use logarithmic ML energy in energy_of_struct */
PUBLIC  int uniq_ML   = 0;  /* do ML decomposition uniquely (for subopt) */
PUBLIC  int cut_point = -1; /* set to first pos of second seq for cofolding */
PUBLIC  int eos_debug = 0;  /* verbose info from energy_of_struct */

/*
#################################
# PRIVATE VARIABLES             #
#################################
*/
PRIVATE int     *indx     = NULL; /* index for moving in the triangle matrices c[] and fMl[]*/
PRIVATE int     *c        = NULL; /* energy array, given that i-j pair */
PRIVATE int     *cc       = NULL; /* linear array for calculating canonical structures */
PRIVATE int     *cc1      = NULL; /*   "     "        */
PRIVATE int     *f5       = NULL; /* energy of 5' end */
PRIVATE int     *f53      = NULL; /* energy of 5' end with 3' nucleotide not available for mismatches */
PRIVATE int     *fML      = NULL; /* multi-loop auxiliary energy array */
PRIVATE int     *fM1      = NULL; /* second ML array, only for subopt */
PRIVATE int     *fM2      = NULL; /* fM2 = multiloop region with exactly two stems, extending to 3' end        */
PRIVATE int     *Fmi      = NULL; /* holds row i of fML (avoids jumps in memory) */
PRIVATE int     *DMLi     = NULL; /* DMLi[j] holds MIN(fML[i,k]+fML[k+1,j])  */
PRIVATE int     *DMLi1    = NULL; /*             MIN(fML[i+1,k]+fML[k+1,j])  */
PRIVATE int     *DMLi2    = NULL; /*             MIN(fML[i+2,k]+fML[k+1,j])  */
PRIVATE int     *DMLi_a   = NULL; /* DMLi_a[j] holds min energy for at least two multiloop stems in [i,j], where j is available for dangling onto a surrounding stem */
PRIVATE int     *DMLi_o   = NULL; /* DMLi_o[j] holds min energy for at least two multiloop stems in [i,j], where j is unavailable for dangling onto a surrounding stem */
PRIVATE int     *DMLi1_a  = NULL;
PRIVATE int     *DMLi1_o  = NULL;
PRIVATE int     *DMLi2_a  = NULL;
PRIVATE int     *DMLi2_o  = NULL;
PRIVATE int     Fc, FcH, FcI, FcM;  /* parts of the exterior loop energies */
PRIVATE sect    sector[MAXSECTORS]; /* stack of partial structures for backtracking */
PRIVATE char    *ptype = NULL;      /* precomputed array of pair types */
PRIVATE short   *S = NULL, *S1 = NULL;
PRIVATE paramT  *P          = NULL;
PRIVATE int     init_length = -1;
PRIVATE int     *BP = NULL; /* contains the structure constrainsts: BP[i]
                        -1: | = base must be paired
                        -2: < = base must be paired with j<i
                        -3: > = base must be paired with j>i
                        -4: x = base must not pair
                        positive int: base is paired with int      */
PRIVATE short   *pair_table         = NULL; /* needed by energy of struct */
PRIVATE bondT   *base_pair2         = NULL; /* this replaces base_pair from fold_vars.c */
PRIVATE int     circular            = 0;
PRIVATE int     struct_constrained  = 0;
PRIVATE int     with_gquad          = 0;

PRIVATE int     *ggg = NULL;    /* minimum free energies of the gquadruplexes */

#ifdef _OPENMP

#pragma omp threadprivate(indx, c, cc, cc1, f5, f53, fML, fM1, fM2, Fmi,\
                          DMLi, DMLi1, DMLi2, DMLi_a, DMLi_o, DMLi1_a, DMLi1_o, DMLi2_a, DMLi2_o,\
                          Fc, FcH, FcI, FcM,\
                          sector, ptype, S, S1, P, init_length, BP, pair_table, base_pair2, circular, struct_constrained,\
                          ggg, with_gquad)

#endif

/*
#################################
# PRIVATE FUNCTION DECLARATIONS #
#################################
*/
PRIVATE void  get_arrays(unsigned int size);
PRIVATE int   stack_energy(int i, const char *string, int verbostiy_level);
PRIVATE int   energy_of_extLoop_pt(int i, short *pair_table);
PRIVATE int   energy_of_ml_pt(int i, short *pt);
PRIVATE int   ML_Energy(int i, int is_extloop);
PRIVATE void  make_ptypes(const short *S, const char *structure, paramT *P);
PRIVATE void  backtrack(const char *sequence, int s);
PRIVATE int   fill_arrays(const char *sequence);
PRIVATE void  fill_arrays_circ(const char *string, int *bt);
PRIVATE void  init_fold(int length, paramT *parameters);
/* needed by cofold/eval */
PRIVATE int   cut_in_loop(int i);

/* deprecated functions */
/*@unused@*/
int oldLoopEnergy(int i, int j, int p, int q, int type, int type_2);
int LoopEnergy(int n1, int n2, int type, int type_2, int si1, int sj1, int sp1, int sq1);
int HairpinE(int size, int type, int si1, int sj1, const char *string);


/*
#################################
# BEGIN OF FUNCTION DEFINITIONS #
#################################
*/

/* allocate memory for folding process */
PRIVATE void init_fold(int length, paramT *parameters){

#ifdef _OPENMP
/* Explicitly turn off dynamic threads */
  omp_set_dynamic(0);
#endif

  if (length<1) nrerror("initialize_fold: argument must be greater 0");
  free_arrays();
  get_arrays((unsigned) length);
  init_length=length;

  indx = get_indx((unsigned)length);

  update_fold_params_par(parameters);
}

/*--------------------------------------------------------------------------*/

PRIVATE void get_arrays(unsigned int size){
  if(size >= (unsigned int)sqrt((double)INT_MAX))
    nrerror("get_arrays@fold.c: sequence length exceeds addressable range");

  c     = (int *) space(sizeof(int)*((size*(size+1))/2+2));
  fML   = (int *) space(sizeof(int)*((size*(size+1))/2+2));
  if (uniq_ML)
    fM1 = (int *) space(sizeof(int)*((size*(size+1))/2+2));

  ptype = (char *)space(sizeof(char)*((size*(size+1))/2+2));
  f5    = (int *) space(sizeof(int)*(size+2));
  f53   = (int *) space(sizeof(int)*(size+2));
  cc    = (int *) space(sizeof(int)*(size+2));
  cc1   = (int *) space(sizeof(int)*(size+2));
  Fmi   = (int *) space(sizeof(int)*(size+1));
  DMLi  = (int *) space(sizeof(int)*(size+1));
  DMLi1 = (int *) space(sizeof(int)*(size+1));
  DMLi2 = (int *) space(sizeof(int)*(size+1));

  DMLi_a  = (int *) space(sizeof(int)*(size+1));
  DMLi_o  = (int *) space(sizeof(int)*(size+1));
  DMLi1_a = (int *) space(sizeof(int)*(size+1));
  DMLi1_o = (int *) space(sizeof(int)*(size+1));
  DMLi2_a = (int *) space(sizeof(int)*(size+1));
  DMLi2_o = (int *) space(sizeof(int)*(size+1));

  base_pair2 = (bondT *) space(sizeof(bondT)*(1+size/2));

  /* extra array(s) for circfold() */
  if(circular) fM2 =  (int *) space(sizeof(int)*(size+2));
}

/*--------------------------------------------------------------------------*/

PUBLIC void free_arrays(void){
  if(indx)      free(indx);
  if(c)         free(c);
  if(fML)       free(fML);
  if(f5)        free(f5);
  if(f53)       free(f53);
  if(cc)        free(cc);
  if(cc1)       free(cc1);
  if(ptype)     free(ptype);
  if(fM1)       free(fM1);
  if(fM2)       free(fM2);
  if(base_pair2) free(base_pair2);
  if(Fmi)       free(Fmi);
  if(DMLi)      free(DMLi);
  if(DMLi1)     free(DMLi1);
  if(DMLi2)     free(DMLi2);
  if(DMLi_a)    free(DMLi_a);
  if(DMLi_o)    free(DMLi_o);
  if(DMLi1_a)   free(DMLi1_a);
  if(DMLi1_o)   free(DMLi1_o);
  if(DMLi2_a)   free(DMLi2_a);
  if(DMLi2_o)   free(DMLi2_o);
  if(P)         free(P);
  if(ggg)       free(ggg);

  indx = c = fML = f5 = f53 = cc = cc1 = fM1 = fM2 = Fmi = DMLi = DMLi1 = DMLi2 = ggg = NULL;
  DMLi_a = DMLi_o = DMLi1_a = DMLi1_o = DMLi2_a = DMLi2_o = NULL;
  ptype       = NULL;
  base_pair   = NULL;
  base_pair2  = NULL;
  P           = NULL;
  init_length = 0;
}

/*--------------------------------------------------------------------------*/

PUBLIC void export_fold_arrays( int **f5_p,
                                int **c_p,
                                int **fML_p,
                                int **fM1_p,
                                int **indx_p,
                                char **ptype_p){
  /* make the DP arrays available to routines such as subopt() */
  *f5_p     = f5;
  *c_p      = c;
  *fML_p    = fML;
  *fM1_p    = fM1;
  *indx_p   = indx;
  *ptype_p  = ptype;
}

PUBLIC void export_fold_arrays_par( int **f5_p,
                                    int **c_p,
                                    int **fML_p,
                                    int **fM1_p,
                                    int **indx_p,
                                    char **ptype_p,
                                    paramT **P_p){
  export_fold_arrays(f5_p, c_p, fML_p, fM1_p, indx_p,ptype_p);
  *P_p = P;
}

PUBLIC void export_circfold_arrays( int *Fc_p,
                                    int *FcH_p,
                                    int *FcI_p,
                                    int *FcM_p,
                                    int **fM2_p,
                                    int **f5_p,
                                    int **c_p,
                                    int **fML_p,
                                    int **fM1_p,
                                    int **indx_p,
                                    char **ptype_p){
  /* make the DP arrays available to routines such as subopt() */
  *f5_p     = f5;
  *c_p      = c;
  *fML_p    = fML;
  *fM1_p    = fM1;
  *fM2_p    = fM2;
  *Fc_p     = Fc;
  *FcH_p    = FcH;
  *FcI_p    = FcI;
  *FcM_p    = FcM;
  *indx_p   = indx;
  *ptype_p  = ptype;
}

PUBLIC void export_circfold_arrays_par( int *Fc_p,
                                    int *FcH_p,
                                    int *FcI_p,
                                    int *FcM_p,
                                    int **fM2_p,
                                    int **f5_p,
                                    int **c_p,
                                    int **fML_p,
                                    int **fM1_p,
                                    int **indx_p,
                                    char **ptype_p,
                                    paramT **P_p){
  export_circfold_arrays(Fc_p, FcH_p, FcI_p, FcM_p, fM2_p, f5_p, c_p, fML_p, fM1_p, indx_p, ptype_p);
  *P_p = P;
}
/*--------------------------------------------------------------------------*/



#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>

// Assuming these are the necessary shared declarations/definitions/imports
struct paramT {};
struct bondT {
    int i, j;
};
extern paramT* P;
extern float temperature;
extern float P->temperature;
extern int init_length;
extern float BONUS;
extern int with_gquad;
extern bool struct_constrained;
extern bool (*make_ptypes)(int*, const char*, char*);
extern int (*fill_arrays)(const char*);
extern int (*fill_arrays_circ)(const char*, int*);
extern void (*backtrack)(const char*, int);
extern void (*parenthesis_structure)(char*, bondT*, int);
extern void (*letter_structure)(char*, bondT*, int);
extern int (*update_fold_params)();
extern int (*init_fold)(int, paramT*);
extern int (*fill_lost_struct)();
extern char backtrack_type;
extern int (*encode_sequence)(const char*, int);
extern void (*export_fold_arrays)(int**, int**, int**, int**, int**, char**);
extern int **f5, **c, **fML, **fM1, **fM2, **indx, *Fc, *FcH, *FcI, *FcM;
extern char **ptype;

PUBLIC float fold_par(
    const char *string,
    char *structure,
    paramT *parameters,
    int is_constrained,
    int is_circular
) {
    int i, length, energy, bonus, bonus_cnt, s;

    bonus = 0;
    bonus_cnt = 0;
    s = 0;
    bool circular = is_circular;
    struct_constrained = is_constrained;
    length = static_cast<int>(strlen(string));

#ifdef _OPENMP
    init_fold(length, parameters);
#else
    if (parameters) init_fold(length, parameters);
    else if (length > init_length) init_fold(length, parameters);
    else if (std::fabs(P->temperature - temperature) > 1e-6) update_fold_params();
#endif

    with_gquad = P->model_details.gquad;
    int* S = encode_sequence(string, 0);
    int* S1 = encode_sequence(string, 1);
    int* BP = static_cast<int*>(std::malloc(sizeof(int) * (length + 2)));
    if (with_gquad) {
        if (BP) std::free(base_pair2);
        bondT* base_pair2 = static_cast<bondT*>(std::malloc(sizeof(bondT) * (4 * (1 + length / 2))));
    }

    make_ptypes(S, structure, P);

    energy = fill_arrays(string);

    if (circular) {
        fill_arrays_circ(string, &s);
        energy = *Fc;
    }
    backtrack(string, s);

#ifdef PAREN
    parenthesis_structure(structure, base_pair2, length);
#else
    letter_structure(structure, base_pair2, length);
#endif

    base_pair = base_pair2;

    for (i = 1; i <= length; ++i) {
        if ((BP[i] < 0) && (BP[i] > -4)) {
            bonus_cnt++;
            if ((BP[i] == -3) && (structure[i - 1] == ')')) bonus++;
            if ((BP[i] == -2) && (structure[i - 1] == '(')) bonus++;
            if ((BP[i] == -1) && (structure[i - 1] != '.')) bonus++;
        }

        if (BP[i] > i) {
            for (int l = 1; l <= base_pair2[0].i; l++) {
                if (base_pair2[l].i != base_pair2[l].j && (i == base_pair2[l].i) && (BP[i] == base_pair2[l].j)) {
                    bonus_cnt++;
                    bonus++;
                }
            }