void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {		  

  if(nrhs < 2 || nrhs==3 || nrhs > 4) {
    mexErrMsgTxt("expected either 2 or 4 input arguments:\n [scr_matrix] = compute_score_matrix(X,score_fcts[,min_feat_values,max_feat_values])\n");
    return;
  }
  
  if(nlhs != 1) {
    mexErrMsgTxt("expected either 2 or 4 input arguments:\n [scr_matrix] = compute_score_matrix(X,score_fcts[,min_feat_values,max_feat_values])\n");
    return;
  }
  
  // read input arguments
  int arg = 0;

  double *X_ptr;
  const int X_M = mxGetM(prhs[arg]);
  const int X_N = mxGetN(prhs[arg]);
  X_ptr = mxGetPr(prhs[arg]);
  ++arg;
  
  score_plif_struct *scr_ptr;
  int scr_M = 0; int scr_N = 0;
  scr_ptr = read_score_plif_struct(prhs[arg], scr_M, scr_N);
  ++arg;

  const double INF = INFINITY;
  const int L = X_N;                      // length of the given example
  const int n_states = scr_N;             // number of states
  const int n_feats = scr_M;              // number of features

  double *min_feat_val;
  double *max_feat_val;
  if (nrhs == 4) {
    min_feat_val = mxGetPr(prhs[arg]);
    ++arg;
    
    max_feat_val = mxGetPr(prhs[arg]);
    ++arg;
  } else {
    // intialize min_feat_val and max_feat_val to -inf and +inf, respectively
    mxArray *mn = mxCreateDoubleMatrix(n_states, n_feats, mxREAL);
    min_feat_val = mxGetPr(mn);
    mxArray *mx = mxCreateDoubleMatrix(n_states, n_feats, mxREAL);
    max_feat_val = mxGetPr(mx);
    for (int f=0; f<n_feats; ++f) {       // for all features
      for (int s=0; s<n_states; ++s) {    // for all states
	min_feat_val[f*n_states+s] = -INF;
	max_feat_val[f*n_states+s] =  INF;
      }
    }
  }

  // compute scores along the possible paths for X
  plhs[0] = mxCreateDoubleMatrix(n_states, L, mxREAL);
  double *pp = mxGetPr(plhs[0]);
  // will already be initialized to 0.0 by mxCreateDoubleMatrix

  // scores for real-valued features
  for (int pos=0; pos<L; ++pos) {         // for all positions in given example
    for (int f=0; f<n_feats; ++f) {       // for all features
      for (int s=0; s<n_states; ++s) {    // for all states
	const int scr_idx = s*n_feats+f;
	const int pp_idx = pos*n_states+s;
	const int X_idx = pos*X_M+f;

	/*
	if (pos == 0) {
	  printf("f=%i, s=%i, min_feat_val[s,f]=%f, max_feat_val[s,f]=%f\n", f, s, min_feat_val[f*n_states+s], max_feat_val[f*n_states+s]);
	}
	*/

	if (X_ptr[X_idx] >= min_feat_val[f*n_states+s] && X_ptr[X_idx] <= max_feat_val[f*n_states+s]) {
	  pp[pp_idx] += lookup_score_plif(&scr_ptr[scr_idx], X_ptr[X_idx]);
	  //	  if (pos == 0)
	  //	    printf("  permitted\n");
	} else {
	  pp[pp_idx] = -INF;
	}
      }
    }
  }
  	
  // clean up
  delete_score_plif_struct_matrix(scr_ptr, scr_M, scr_N);
}
struct score_plif_struct* read_score_plif_struct(const mxArray *mx_score_plif_matrix, int &M, int &N) {
    int n_fields = mxGetNumberOfFields(mx_score_plif_matrix);
    int n_elems  = mxGetNumberOfElements(mx_score_plif_matrix);
//  fprintf(stderr, "n_fields %i, n_elems %i\n", n_fields, n_elems);

    M = mxGetM(mx_score_plif_matrix);
    N = mxGetN(mx_score_plif_matrix);

//  fprintf(stderr, "Initializing score_plif struct matrix of dimensions %i x %i\n", M, N) ;
    struct score_plif_struct *SCR = new struct score_plif_struct[M*N];
    for (int i=0; i<M; ++i) {
        for(int j=0; j<N; ++j) {
            init_score_plif_struct(SCR[i*N+j]);
//	fprintf(stderr, "initialized field (%i,%i)\n", i, j);
        }
    }

//  fprintf(stderr, "Reading limits...\n") ;
    int lim_f_num = mxGetFieldNumber(mx_score_plif_matrix, "limits");
    int scr_f_num = mxGetFieldNumber(mx_score_plif_matrix, "scores");
    int dim_f_num = mxGetFieldNumber(mx_score_plif_matrix, "dim");
//  fprintf(stderr, "%i  %i  %i", lim_f_num, scr_f_num, dim_f_num) ;

    for(int j=0; j<n_elems; ++j) {
        const mxArray *lim = mxGetFieldByNumber(mx_score_plif_matrix, j, lim_f_num);
        const mxArray *scr = mxGetFieldByNumber(mx_score_plif_matrix, j, scr_f_num);
        const mxArray *dim = mxGetFieldByNumber(mx_score_plif_matrix, j, dim_f_num);
//    fprintf(stderr, "%s  %s  %s", mxGetClassName(lim), mxGetClassName(scr),  mxGetClassName(dim)) ;

        if (lim==NULL || !mxIsDouble(lim)) {
            fprintf(stderr, "limits are expected to be doubles\n");
            delete_score_plif_struct_matrix(SCR,M,N);
            return NULL;
        }

        if (scr==NULL || !mxIsDouble(scr)) {
            fprintf(stderr, "scores are expected to be doubles\n");
            delete_score_plif_struct_matrix(SCR,M,N);
            return NULL;
        }

        if (dim==NULL || !mxIsNumeric(dim)) {
            fprintf(stderr, "dim is expected to be a single (integer) value\n");
            delete_score_plif_struct_matrix(SCR,M,N);
            return NULL;
        }

        const double *lim_ptr = mxGetPr(lim);
        const double *scr_ptr = mxGetPr(scr);
        const int feat = (int) *mxGetPr(dim);
        const int len = mxGetN(lim);

        SCR[j].len = len ;
        SCR[j].feat_idx = feat;
        SCR[j].limits = new double[len];
        SCR[j].scores = new double[len];
        for (int i=0; i<len; ++i) {
            SCR[j].limits[i]=lim_ptr[i];
            SCR[j].scores[i]=scr_ptr[i];
        }
    }
    return SCR;
}