Example #1
0
def _tau_to_kappa(tau):
    """Using non-linear optimization, convert the NODDI-DTI Tau variables to NODDI kappa's.

    Args:
        tau (ndarray): the list of tau's per voxel.

    Returns:
        ndarray: the list of corresponding kappa's
    """
    tau_func = SimpleCLFunction.from_string('''
        double tau(double kappa){
            if(kappa < 1e-12){
                return 1/3.0;
            }
            return 0.5 * ( 1 / ( sqrt(kappa) * dawson(sqrt(kappa) ) ) - 1/kappa);
        }''',
                                            dependencies=[dawson()])

    objective_func = SimpleCLFunction.from_string('''
        double tau_to_kappa(local const mot_float_type* const x, void* data, local mot_float_type* objective_list){
            return pown(tau(x[0]) - ((_tau_to_kappa_data*)data)->tau, 2); 
        }
    ''',
                                                  dependencies=[tau_func])

    kappa = minimize(objective_func,
                     np.ones_like(tau),
                     data=Struct(
                         {'tau': Array(tau, 'mot_float_type', as_scalar=True)},
                         '_tau_to_kappa_data')).x
    kappa[kappa > 64] = 1
    kappa[kappa < 0] = 1
    return kappa
Example #2
0
def _tau_to_kappa(tau):
    """Using non-linear optimization, convert the NODDI-DTI Tau variables to NODDI kappa's.

    Args:
        tau (ndarray): the list of tau's per voxel.

    Returns:
        ndarray: the list of corresponding kappa's
    """
    tau_func = SimpleCLFunction.from_string('''
        mot_float_type tau(mot_float_type kappa){
            if(kappa < 1e-12){
                return 1/3.0;
            }
            return 0.5 * ( 1 / ( sqrt(kappa) * dawson(sqrt(kappa) ) ) - 1/kappa);
        }''',
                                            dependencies=[dawson()])

    objective_func = SimpleCLFunction.from_string('''
        double tau_to_kappa(local const mot_float_type* const x, void* data, local mot_float_type* objective_list){
            return pown(tau(x[0]) - *((mot_float_type*)data), 2); 
        }
    ''',
                                                  dependencies=[tau_func])

    kappa = minimize(objective_func,
                     np.ones_like(tau),
                     data=Array(tau, 'mot_float_type')).x
    return np.clip(kappa, 0, 64)
Example #3
0
def parse_cl_function(cl_code, dependencies=()):
    """Parse the given OpenCL string to a single SimpleCLFunction.

    If the string contains more than one function, we will return only the last, with all the other added as a
    dependency.

    Args:
        cl_code (str): the input string containing one or more functions.
        dependencies (Iterable[CLCodeObject]): The list of CL libraries this function depends on

    Returns:
        mot.lib.cl_function.SimpleCLFunction: the CL function for the last function in the given strings.
    """
    from mot.lib.cl_function import SimpleCLFunction

    def separate_cl_functions(input_str):
        """Separate all the OpenCL functions.

        This creates a list of strings, with for each function found the OpenCL code.

        Args:
            input_str (str): the string containing one or more functions.

        Returns:
            list: a list of strings, with one string per found CL function.
        """
        class Semantics:

            def __init__(self):
                self._functions = []

            def result(self, ast):
                return self._functions

            def arglist(self, ast):
                if ast == '()':
                    return '()'
                return '({})'.format(', '.join(ast))

            def function(self, ast):
                def join(items):
                    result = ''
                    for item in items:
                        if isinstance(item, str):
                            result += item
                        else:
                            result += join(item)
                    return result

                self._functions.append(join(ast).strip())
                return ast

        return _extract_cl_functions_parser.parse(input_str, semantics=Semantics())

    functions = separate_cl_functions(cl_code)
    return SimpleCLFunction.from_string(functions[-1], dependencies=list(dependencies or []) + [
        SimpleCLFunction.from_string(s) for s in functions[:-1]])
Example #4
0
def parse_cl_function(cl_code, dependencies=(), cl_extra=None):
    """Parse the given OpenCL string to a single SimpleCLFunction.

    If the string contains more than one function, we will return only the last, with all the other added as a
    dependency.

    Args:
        cl_code (str): the input string containing one or more functions.
        dependencies (list or tuple of CLLibrary): The list of CL libraries this function depends on
        cl_extra (str): extra CL code for this function that does not warrant an own function.
            This is prepended to the function body.

    Returns:
        mot.lib.cl_function.SimpleCLFunction: the CL function for the last function in the given strings.
    """
    from mot.lib.cl_function import SimpleCLFunction

    def separate_cl_functions(input_str):
        """Separate all the OpenCL functions.

        This creates a list of strings, with for each function found the OpenCL code.

        Args:
            input_str (str): the string containing one or more functions.

        Returns:
            list: a list of strings, with one string per found CL function.
        """
        class Semantics:
            def __init__(self):
                self._functions = []

            def result(self, ast):
                return self._functions

            def function(self, ast):
                def join(items):
                    result = ''
                    for item in items:
                        if isinstance(item, str):
                            result += item
                        else:
                            result += join(item)
                    return result

                self._functions.append(join(ast).strip())
                return ast

        return _cl_functions_parser.parse(input_str, semantics=Semantics())

    functions = separate_cl_functions(cl_code)
    return SimpleCLFunction.from_string(
        functions[-1],
        dependencies=list(dependencies or []) +
        [SimpleCLFunction.from_string(s) for s in functions[:-1]],
        cl_extra=cl_extra)
Example #5
0
    def encode_decode(self,
                      parameters,
                      kernel_data=None,
                      cl_runtime_info=None):
        """First apply an encoding operation and then apply a decoding operation again.

        This can be used to enforce boundary conditions in the parameters.

        Args:
            parameters (ndarray): The parameters to transform
            kernel_data (dict[str: mot.lib.utils.KernelData]): the additional data to load
            cl_runtime_info (mot.configuration.CLRuntimeInfo): the runtime information

        Returns:
            ndarray: The array with the transformed parameters.
        """
        encode_func = self.get_encode_function()
        decode_func = self.get_decode_function()

        func = SimpleCLFunction.from_string(
            '''
            void encode_decode_parameters(void* data, local mot_float_type* x){
                ''' + encode_func.get_cl_function_name() + '''(data, x);
                ''' + decode_func.get_cl_function_name() + '''(data, x);
            }
        ''',
            dependencies=[encode_func, decode_func])
        return self._transform_parameters(func,
                                          parameters,
                                          kernel_data,
                                          cl_runtime_info=cl_runtime_info)
Example #6
0
def _minimize_powell(func, x0, cl_runtime_info, data=None, options=None):
    """
    Options:
        patience (int): Used to set the maximum number of iterations to patience*(number_of_parameters+1)
        reset_method (str): one of 'EXTRAPOLATED_POINT' or 'RESET_TO_IDENTITY' lower case or upper case.
        patience_line_search (int): the patience of the searching algorithm. Defaults to the
            same patience as for the Powell algorithm itself.
    """
    options = _clean_options('Powell', options)

    nmr_problems = x0.shape[0]
    nmr_parameters = x0.shape[1]

    kernel_data = {'model_parameters': Array(x0, ctype='mot_float_type', mode='rw'),
                   'data': data}

    eval_func = SimpleCLFunction.from_string('''
        double evaluate(local mot_float_type* x, void* data){
            return ''' + func.get_cl_function_name() + '''(x, data, 0);
        }
    ''', dependencies=[func])

    optimizer_func = Powell(eval_func, nmr_parameters, **options)

    return_code = optimizer_func.evaluate(
        kernel_data, nmr_problems,
        use_local_reduction=all(env.is_gpu for env in cl_runtime_info.get_cl_environments()),
        cl_runtime_info=cl_runtime_info)

    return OptimizeResults({'x': kernel_data['model_parameters'].get_data(),
                            'status': return_code})
Example #7
0
def _minimize_levenberg_marquardt(func, x0, nmr_observations, cl_runtime_info, data=None, options=None):
    options = _clean_options('Levenberg-Marquardt', options)

    nmr_problems = x0.shape[0]
    nmr_parameters = x0.shape[1]

    if nmr_observations < x0.shape[1]:
        raise ValueError('The number of instances per problem must be greater than the number of parameters')

    kernel_data = {'model_parameters': Array(x0, ctype='mot_float_type', mode='rw'),
                   'data': data,
                   'fjac': Zeros((nmr_problems, nmr_parameters, nmr_observations), ctype='mot_float_type',
                                 mode='rw')}

    eval_func = SimpleCLFunction.from_string('''
        void evaluate(local mot_float_type* x, void* data, local mot_float_type* result){
            ''' + func.get_cl_function_name() + '''(x, data, result);
        }
    ''', dependencies=[func])

    optimizer_func = LevenbergMarquardt(eval_func, nmr_parameters, nmr_observations, jacobian_func=None, **options)

    return_code = optimizer_func.evaluate(
        kernel_data, nmr_problems,
        use_local_reduction=all(env.is_gpu for env in cl_runtime_info.get_cl_environments()),
        cl_runtime_info=cl_runtime_info)

    return OptimizeResults({'x': kernel_data['model_parameters'].get_data(),
                            'status': return_code})
Example #8
0
def _derivation_kernel(objective_func, nmr_params, nmr_steps, step_ratio,
                       parameter_transform_func):
    coords = [(x, y) for x, y in itertools.combinations_with_replacement(
        range(nmr_params), 2)]
    func = _get_compute_functions_cl(objective_func, nmr_params, nmr_steps,
                                     step_ratio, parameter_transform_func)

    return SimpleCLFunction.from_string('''
        void compute(local mot_float_type* parameters,
                     global float* parameter_scalings_inv,
                     global float* initial_step,
                     global double* step_evaluates,
                     void* data){
                                 
            double f_x_input = _calculate_function(data, parameters);
            
            uint coords[''' + str(len(coords)) + '''][2] = {
                ''' + ', '.join('{{{}, {}}}'.format(*c) for c in coords) + '''
            };
            
            for(uint coord_ind = 0; coord_ind < ''' + str(len(coords)) +
                                        '''; coord_ind++){
                _compute_steps(data, parameters, f_x_input, coords[coord_ind][0], coords[coord_ind][1], 
                               step_evaluates + coord_ind * ''' +
                                        str(nmr_steps) +
                                        ''', parameter_scalings_inv,
                               initial_step);
            }
        }
    ''',
                                        cl_extra=func)
Example #9
0
    def _get_signal_estimates(self, roi_indices):
        self._model.set_input_data(self._input_data, suppress_warnings=True)

        parameters = self._x_opt_array[roi_indices]
        kernel_data = {
            'data':
            self._model.get_kernel_data().get_subset(roi_indices),
            'parameters':
            Array(parameters, ctype='mot_float_type'),
            'estimates':
            Zeros((parameters.shape[0], self._model.get_nmr_observations()),
                  'mot_float_type')
        }

        eval_function_info = self._model.get_model_eval_function()
        simulate_function = SimpleCLFunction.from_string(
            '''
                void simulate(void* data, local mot_float_type* parameters, global mot_float_type* estimates){
                    for(uint i = 0; i < ''' +
            str(self._model.get_nmr_observations()) + '''; i++){
                        estimates[i] = ''' +
            eval_function_info.get_cl_function_name() +
            '''(data, parameters, i);
                    }
                }
            ''',
            dependencies=[eval_function_info])

        simulate_function.evaluate(kernel_data, parameters.shape[0])
        return kernel_data['estimates'].get_data()
Example #10
0
 def __init__(self, cl_code, **kwargs):
     func = SimpleCLFunction.from_string(cl_code, **kwargs)
     super().__init__(func.get_return_type(),
                      func.get_cl_function_name(),
                      func.get_parameters(),
                      func.get_cl_body(),
                      dependencies=func.get_dependencies(),
                      cl_extra=func.get_cl_extra())
def _get_numdiff_hessian_element_func(objective_func, nmr_steps, step_ratio):
    """Return a function to compute one element of the Hessian matrix."""
    return SimpleCLFunction.from_string(
        '''
        /**
         * Compute the Hessian using (possibly) multiple steps with various interpolations.
         */
        void _numdiff_hessian_element(
                void* data, local mot_float_type* x_tmp, mot_float_type f_x_input,
                uint px, uint py, global float* initial_step, global double* derivative,
                global double* error, local double* scratch){

            const uint nmr_steps = ''' + str(nmr_steps) + ''';
            uint nmr_steps_remaining = nmr_steps;

            local double* scratch_ind = scratch;
            local double* steps = scratch_ind;      scratch_ind += nmr_steps;
            local double* errors = scratch_ind;     scratch_ind += nmr_steps - 1;
            local double* steps_tmp = scratch_ind;  scratch_ind += nmr_steps;

            if(get_local_id(0) == 0){
                for(int i = 0; i < nmr_steps - 1; i++){
                    errors[i] = 0;
                }
            }
            barrier(CLK_LOCAL_MEM_FENCE);

            _numdiff_hessian_steps(data, x_tmp, f_x_input, px, py, steps, initial_step);

            if(nmr_steps_remaining > 1){
                nmr_steps_remaining = _numdiff_hessian_richardson_extrapolation(steps);
                barrier(CLK_LOCAL_MEM_FENCE);
            }

            if(nmr_steps_remaining >= 3){
                nmr_steps_remaining = _numdiff_wynn_extrapolation(steps, errors, nmr_steps_remaining);
                barrier(CLK_LOCAL_MEM_FENCE);
            }

            if(nmr_steps_remaining > 1){
                _numdiff_find_best_step(steps, errors, steps_tmp, nmr_steps_remaining);
                barrier(CLK_LOCAL_MEM_FENCE);
            }

            if(get_local_id(0) == 0){
                *derivative = steps[0];
                *error = errors[0];
            }
        }
    ''',
        dependencies=[
            _get_numdiff_hessian_steps_func(objective_func, nmr_steps,
                                            step_ratio),
            _get_numdiff_hessian_richardson_extrapolation_func(
                nmr_steps, step_ratio),
            _get_numdiff_wynn_extrapolation_func(),
            _get_numdiff_find_best_step_func()
        ])
Example #12
0
def get_log_prior_function():
    return SimpleCLFunction.from_string('''
        double germanTank_logPrior(local const mot_float_type* const x, void* data){
            uint nmr_tanks = (uint)round(x[0]);
            return discrete_uniform(
                nmr_tanks, ((_model_data*)data)->lower_bounds[0], ((_model_data*)data)->upper_bounds[0]);
        }
    ''',
                                        dependencies=[discrete_uniform_func()])
Example #13
0
def discrete_uniform_func():
    return SimpleCLFunction.from_string('''
        float discrete_uniform(uint x, uint lower, uint upper){
            if(x < lower || x > upper){
                return -INFINITY;
            }
            return -log((float)(upper-lower));
        }
    ''')
Example #14
0
def _minimize_levenberg_marquardt(func, x0, nmr_observations, cl_runtime_info, lower_bounds, upper_bounds,
                                  use_local_reduction,
                                  constraints_func=None, data=None, options=None):
    options = options or {}
    nmr_problems = x0.shape[0]
    nmr_parameters = x0.shape[1]

    if nmr_observations < x0.shape[1]:
        raise ValueError('The number of instances per problem must be greater than the number of parameters')

    penalty_data, penalty_func = _get_penalty_function(nmr_parameters, constraints_func)

    eval_func = SimpleCLFunction.from_string('''
        void evaluate(local mot_float_type* x, void* data, local mot_float_type* result){
            double penalty = _mle_penalty(
                x,
                ((_lm_eval_func_data*)data)->data,
                ((_lm_eval_func_data*)data)->lower_bounds,
                ((_lm_eval_func_data*)data)->upper_bounds,
                ''' + str(options.get('penalty_weight', 1e30)) + ''',
                ((_lm_eval_func_data*)data)->penalty_data
            );

            ''' + func.get_cl_function_name() + '''(x, ((_lm_eval_func_data*)data)->data, result);

            if(get_local_id(0) == 0){
                for(int j = 0; j < ''' + str(nmr_observations) + '''; j++){
                    result[j] += penalty;
                }
            }
            barrier(CLK_LOCAL_MEM_FENCE);
        }
    ''', dependencies=[func, penalty_func])

    jacobian_func = _lm_numdiff_jacobian(eval_func, nmr_parameters, nmr_observations)

    optimizer_func = LevenbergMarquardt(eval_func, nmr_parameters, nmr_observations, jacobian_func,
                                        **_clean_options('Levenberg-Marquardt', options))

    kernel_data = {'model_parameters': Array(x0, ctype='mot_float_type', mode='rw'),
                   'data': Struct({'data': data,
                                   'lower_bounds': lower_bounds,
                                   'upper_bounds': upper_bounds,
                                   'penalty_data': penalty_data,
                                   'jacobian_x_tmp': LocalMemory('mot_float_type', nmr_observations)
                                   },
                                  '_lm_eval_func_data')}
    kernel_data.update(optimizer_func.get_kernel_data())

    return_code = optimizer_func.evaluate(
        kernel_data, nmr_problems,
        use_local_reduction=use_local_reduction and all(env.is_gpu for env in cl_runtime_info.cl_environments),
        cl_runtime_info=cl_runtime_info)

    return OptimizeResults({'x': kernel_data['model_parameters'].get_data(),
                            'status': return_code})
Example #15
0
def maximize(func, x0, nmr_observations, **kwargs):
    """Maximization of a function.

    This wraps the objective function to take the negative of the computed values and passes it then on to one
    of the minimization routines.

    Args:
        func (mot.lib.cl_function.CLFunction): A CL function with the signature:

            .. code-block:: c

                double <func_name>(local const mot_float_type* const x,
                                   void* data,
                                   local mot_float_type* objective_list);

            The objective list needs to be filled when the provided pointer is not null. It should contain
            the function values for each observation. This list is used by non-linear least-squares routines,
            and will be squared by the least-square optimizer. This is only used by the ``Levenberg-Marquardt`` routine.

        x0 (ndarray): Initial guess. Array of real elements of size (n, p), for 'n' problems and 'p'
            independent variables.
        nmr_observations (int): the number of observations returned by the optimization function.
        **kwargs: see :func:`minimize`.
    """
    wrapped_func = SimpleCLFunction.from_string(
        '''
        double _negate_''' + func.get_cl_function_name() + '''(
                local mot_float_type* x,
                void* data, 
                local mot_float_type* objective_list){

            double return_val = ''' + func.get_cl_function_name() +
        '''(x, data, objective_list);    

            if(objective_list){
                const uint nmr_observations = ''' + str(nmr_observations) +
        ''';
                uint local_id = get_local_id(0);
                uint workgroup_size = get_local_size(0);

                uint observation_ind;
                for(uint i = 0; i < (nmr_observations + workgroup_size - 1) / workgroup_size; i++){
                    observation_ind = i * workgroup_size + local_id;

                    if(observation_ind < nmr_observations){
                        objective_list[observation_ind] *= -1;    
                    }
                }
            }
            return -return_val;
        }
    ''',
        dependencies=[func])
    kwargs['nmr_observations'] = nmr_observations
    return minimize(wrapped_func, x0, **kwargs)
Example #16
0
    def get_cl_function():
        nmr_params = parameters.shape[1]

        if len(parameters.shape) > 2:
            return SimpleCLFunction.from_string(
                '''
                void compute(global mot_float_type* parameters, 
                             global mot_float_type* log_likelihoods,
                             void* data){
                             
                    local mot_float_type x[''' + str(nmr_params) + '''];

                    for(uint sample_ind = 0; sample_ind < ''' +
                str(parameters.shape[2]) + '''; sample_ind++){
                        for(uint i = 0; i < ''' + str(nmr_params) + '''; i++){
                            x[i] = parameters[i *''' +
                str(parameters.shape[2]) + ''' + sample_ind];
                        }
                        
                        double ll = ''' + ll_func.get_cl_function_name() +
                '''(x, data);
                        if(get_local_id(0) == 0){
                            *(log_likelihoods) = ll;
                        }
                    }
                }
            ''',
                dependencies=[ll_func])

        return SimpleCLFunction.from_string('''
            void compute(local mot_float_type* parameters, 
                         global mot_float_type* log_likelihoods,
                         void* data){
                         
                double ll = ''' + ll_func.get_cl_function_name() +
                                            '''(parameters, data);
                if(get_local_id(0) == 0){
                    *(log_likelihoods) = ll;
                }
            }
        ''',
                                            dependencies=[ll_func])
Example #17
0
def uniform(nmr_distributions,
            nmr_samples,
            low=0,
            high=1,
            ctype='float',
            seed=None):
    """Draw random samples from the Uniform distribution.

    Args:
        nmr_distributions (int): the number of unique continuous_distributions to create
        nmr_samples (int): The number of samples to draw
        low (double): The minimum value of the random numbers
        high (double): The minimum value of the random numbers
        ctype (str): the C type of the output samples
        seed (float): the seed for the RNG

    Returns:
        ndarray: A two dimensional numpy array as (nmr_distributions, nmr_samples).
    """
    if is_scalar(low):
        low = np.ones((nmr_distributions, 1)) * low
    if is_scalar(high):
        high = np.ones((nmr_distributions, 1)) * high

    kernel_data = {
        'low': Array(low, as_scalar=True),
        'high': Array(high, as_scalar=True)
    }

    kernel = SimpleCLFunction.from_string(
        '''
        void compute(double low, double high, global uint* rng_state, global '''
        + ctype + '''* samples){
        
            rand123_data rand123_rng_data = rand123_initialize_data((uint[]){
                rng_state[0], rng_state[1], rng_state[2], rng_state[3], 
                rng_state[4], rng_state[5], 0});
            void* rng_data = (void*)&rand123_rng_data;

            for(uint i = 0; i < ''' + str(nmr_samples) + '''; i++){
                double4 randomnr = rand4(rng_data);
                samples[i] = (''' + ctype +
        ''')(low + randomnr.x * (high - low));
            }
        }
    ''',
        dependencies=[Rand123()])

    return _generate_samples(kernel,
                             nmr_distributions,
                             nmr_samples,
                             ctype,
                             kernel_data,
                             seed=seed)
Example #18
0
def get_log_prior_function(nmr_parameters):
    return SimpleCLFunction.from_string('''
        double rosenbrock_logPrior(local const mot_float_type* const x, void* data){
            for(uint i = 0; i < ''' + str(nmr_parameters) + '''; i++){
                if(x[i] < -10 || x[i] > 10){
                    return log(0.0);
                }
            }
            return log(1.0);
        }
    ''')
Example #19
0
    def _transform_parameters(cl_func, parameters, kernel_data, cl_runtime_info=None):
        cl_named_func = SimpleCLFunction.from_string('''
            void transformParameterSpace(void* data, local mot_float_type* x){
                ''' + cl_func.get_cl_function_name() + '''(data, x);
            }
        ''', dependencies=[cl_func])

        kernel_data = {'data': kernel_data,
                       'x': Array(parameters, ctype='mot_float_type', mode='rw')}

        cl_named_func.evaluate(kernel_data, parameters.shape[0], cl_runtime_info=cl_runtime_info)
        return kernel_data['x'].get_data()
Example #20
0
def _richardson_error_kernel(nmr_steps, nmr_convolutions,
                             richardson_coefficients):
    func = _get_error_estimate_functions_cl(nmr_steps, nmr_convolutions,
                                            richardson_coefficients)

    return SimpleCLFunction.from_string('''
        void convolute(global double* derivatives, global double* richardson_extrapolations, global double* errors){
            _apply_richardson_convolution(derivatives, richardson_extrapolations);
            _compute_richardson_errors(derivatives, richardson_extrapolations, errors);
        }
    ''',
                                        cl_extra=func)
Example #21
0
def get_log_likelihood_function(nmr_parameters):
    return SimpleCLFunction.from_string('''
        double rosenbrock_logLikelihood(local const mot_float_type* const x, void* data){
            double sum = 0;
            double eval;
            for(uint i = 0; i < ''' + str(nmr_parameters) + ''' - 1; i++){
                eval = -(100 * pown(x[i + 1] - pown(x[i], 2), 2) + pown(1 - x[i], 2));
                sum += eval;
            }
            return sum;
        }
    ''')
Example #22
0
def _minimize_powell(func, x0, cl_runtime_info, lower_bounds, upper_bounds, use_local_reduction,
                     constraints_func=None, data=None, options=None):
    """
    Options:
        patience (int): Used to set the maximum number of iterations to patience*(number_of_parameters+1)
        reset_method (str): one of 'EXTRAPOLATED_POINT' or 'RESET_TO_IDENTITY' lower case or upper case.
        patience_line_search (int): the patience of the searching algorithm. Defaults to the
            same patience as for the Powell algorithm itself.
    """
    options = options or {}
    nmr_problems = x0.shape[0]
    nmr_parameters = x0.shape[1]

    penalty_data, penalty_func = _get_penalty_function(nmr_parameters, constraints_func)

    eval_func = SimpleCLFunction.from_string('''
        double evaluate(local mot_float_type* x, void* data){
            double penalty = _mle_penalty(
                x,
                ((_powell_eval_func_data*)data)->data,
                ((_powell_eval_func_data*)data)->lower_bounds,
                ((_powell_eval_func_data*)data)->upper_bounds,
                ''' + str(options.get('penalty_weight', 1e30)) + ''',
                ((_powell_eval_func_data*)data)->penalty_data
            );

            double func_val = ''' + func.get_cl_function_name() + '''(x, ((_powell_eval_func_data*)data)->data, 0);

            if(isnan(func_val)){
                return INFINITY;
            }

            return func_val + penalty;
        }
    ''', dependencies=[func, penalty_func])

    optimizer_func = Powell(eval_func, nmr_parameters, **_clean_options('Powell', options))

    kernel_data = {'model_parameters': Array(x0, ctype='mot_float_type', mode='rw'),
                   'data': Struct({'data': data,
                                   'lower_bounds': lower_bounds,
                                   'upper_bounds': upper_bounds,
                                   'penalty_data': penalty_data}, '_powell_eval_func_data')}
    kernel_data.update(optimizer_func.get_kernel_data())

    return_code = optimizer_func.evaluate(
        kernel_data, nmr_problems,
        use_local_reduction=use_local_reduction and all(env.is_gpu for env in cl_runtime_info.cl_environments),
        cl_runtime_info=cl_runtime_info,)

    return OptimizeResults({'x': kernel_data['model_parameters'].get_data(),
                            'status': return_code})
Example #23
0
def normal(nmr_distributions,
           nmr_samples,
           mean=0,
           std=1,
           ctype='float',
           seed=None):
    """Draw random samples from the Gaussian distribution.

    Args:
        nmr_distributions (int): the number of unique continuous_distributions to create
        nmr_samples (int): The number of samples to draw
        mean (float or ndarray): The mean of the distribution
        std (float or ndarray): The standard deviation or the distribution
        ctype (str): the C type of the output samples
        seed (float): the seed for the RNG

    Returns:
        ndarray: A two dimensional numpy array as (nmr_distributions, nmr_samples).
    """
    if is_scalar(mean):
        mean = np.ones((nmr_distributions, 1)) * mean
    if is_scalar(std):
        std = np.ones((nmr_distributions, 1)) * std

    kernel_data = {
        'mean': Array(mean, as_scalar=True),
        'std': Array(std, as_scalar=True)
    }

    kernel = SimpleCLFunction.from_string('''
        void compute(double mean, double std, global uint* rng_state, global '''
                                          + ctype + '''* samples){
            rand123_data rand123_rng_data = rand123_initialize_data((uint[]){
                rng_state[0], rng_state[1], rng_state[2], rng_state[3], 
                rng_state[4], rng_state[5], 0});
            void* rng_data = (void*)&rand123_rng_data;

            for(uint i = 0; i < ''' + str(nmr_samples) + '''; i++){
                double4 randomnr = randn4(rng_data);
                samples[i] = (''' + ctype + ''')(mean + randomnr.x * std);
            }
        }
    ''',
                                          dependencies=[Rand123()])

    return _generate_samples(kernel,
                             nmr_distributions,
                             nmr_samples,
                             ctype,
                             kernel_data,
                             seed=seed)
Example #24
0
    def _initialize_likelihood_prior(self, positions, log_likelihoods,
                                     log_priors):
        """Initialize the likelihood and the prior using the given positions.

        This is a general method for computing the log likelihoods and log priors for given positions.

        Subclasses can use this to instantiate secondary chains as well.
        """
        func = SimpleCLFunction.from_string(
            '''
            void compute(global mot_float_type* chain_position,
                         global mot_float_type* log_likelihood,
                         global mot_float_type* log_prior,
                         local mot_float_type* x_tmp,
                         void* data){

                bool is_first_work_item = get_local_id(0) == 0;

                if(is_first_work_item){
                    for(uint i = 0; i < ''' + str(self._nmr_params) +
            '''; i++){
                        x_tmp[i] = chain_position[i];
                    }
                    *log_prior = _computeLogPrior(x_tmp, data);
                }
                barrier(CLK_LOCAL_MEM_FENCE);

                *log_likelihood = _computeLogLikelihood(x_tmp, data);
            }
        ''',
            dependencies=[
                self._get_log_prior_cl_func(),
                self._get_log_likelihood_cl_func()
            ])

        kernel_data = {
            'chain_position': Array(positions, 'mot_float_type', mode='rw'),
            'log_likelihood': Array(log_likelihoods,
                                    'mot_float_type',
                                    mode='rw'),
            'log_prior': Array(log_priors, 'mot_float_type', mode='rw'),
            'x_tmp': LocalMemory('mot_float_type', self._nmr_params),
            'data': self._data
        }

        func.evaluate(kernel_data,
                      self._nmr_problems,
                      use_local_reduction=all(
                          env.is_gpu
                          for env in self._cl_runtime_info.cl_environments),
                      cl_runtime_info=self._cl_runtime_info)
Example #25
0
File: base.py Project: 42n4/MOT
    def __init__(self,
                 ll_func,
                 log_prior_func,
                 x0,
                 proposal_stds,
                 use_random_scan=False,
                 finalize_proposal_func=None,
                 **kwargs):
        """An abstract basis for Random Walk Metropolis (RWM) samplers.

        Random Walk Metropolis (RWM) samplers require for every parameter and every modeling instance an proposal
        standard deviation, used in the random walk.

        Args:
            ll_func (mot.lib.cl_function.CLFunction): The log-likelihood function.
            log_prior_func (mot.lib.cl_function.CLFunction): The log-prior function.
            x0 (ndarray): the starting positions for the sampler. Should be a two dimensional matrix
                with for every modeling instance (first dimension) and every parameter (second dimension) a value.
            proposal_stds (ndarray): for every parameter and every modeling instance an initial proposal std.
            use_random_scan (boolean): if we iterate over the parameters in a random order or in a linear order
                at every sample iteration. By default we apply a system scan starting from the first dimension to the
                last. With a random scan we randomize the indices every iteration.
            finalize_proposal_func (mot.lib.cl_function.CLFunction): a CL function to finalize every proposal by
                the sampling routine. This allows the model to change a proposal before computing the
                prior or likelihood probabilities. If None, we will not use this callback.

                As an example, suppose you are sampling a polar coordinate :math:`\theta` defined on
                :math:`[0, 2\pi]` with a random walk Metropolis proposal distribution. This distribution might propose
                positions outside of the range of :math:`\theta`. Of course the model function could deal with that by
                taking the modulus of the input, but then you have to post-process the chain with the same
                transformation. Instead, this function allows changing the proposal before it is put into the model
                and before it will be stored in the chain.

                This function should return a proposal that is equivalent (but not necessarily equal)
                to the provided proposal.

                Signature:

                .. code-block:: c

                    void <func_name>(void* data, local mot_float_type* x);
        """
        super().__init__(ll_func, log_prior_func, x0, **kwargs)
        self._proposal_stds = np.require(
            np.copy(proposal_stds),
            requirements='CAOW',
            dtype=self._cl_runtime_info.mot_float_dtype)
        self._use_random_scan = use_random_scan
        self._finalize_proposal_func = finalize_proposal_func or SimpleCLFunction.from_string(
            'void finalizeProposal(void* data, local mot_float_type* x){}')
Example #26
0
File: base.py Project: 42n4/MOT
    def _get_log_prior_cl_func(self):
        """Get the CL log prior compute function.

        Returns:
            str: the compute function for computing the log prior.
        """
        return SimpleCLFunction.from_string(
            '''
            mot_float_type _computeLogPrior(local const mot_float_type* x, void* data){
                return ''' + self._log_prior_func.get_cl_function_name() +
            '''(x, data);
            }
        ''',
            dependencies=[self._log_prior_func])
Example #27
0
    def wrap_objective_function(self, objective_function, decode_function):
        """Decorates the given objective function with parameter decoding.

        This will change the given parameter vector in-place. This is possible because the optimization routines
        make a copy of the vector before handing it over to the optimization function.

        Args:
            objective_function (mot.lib.cl_function.CLFunction): A CL function with the signature:

                .. code-block:: c

                    double <func_name>(local mot_float_type* x,
                                       void* data,
                                       local mot_float_type* objective_list);
            decode_function (mot.lib.cl_function.CLFunction): An OpenCL function that is used in the CL kernel to
                    transform the parameters from encoded space to model space so they can be used as input to the model.
                    The signature of the CL function is:

                    .. code-block:: c

                        void <fname>(void* data, local mot_float_type* x);

            nmr_parameters (int): the number of parameters we are decoding.

        Returns:
            mot.lib.cl_function.CLFunction: the wrapped objective function.
        """
        return SimpleCLFunction.from_string('''
            double wrapped_''' + objective_function.get_cl_function_name() + '''(
                    local mot_float_type* x,
                    void* data, 
                    local mot_float_type* objective_list){
                
                local mot_float_type* x_tmp = ((objective_function_wrapper_data*)data)->x_tmp;
                
                if(get_local_id(0) == 0){
                    for(uint i = 0; i < ''' + str(self._nmr_parameters) + '''; i++){
                        x_tmp[i] = x[i];
                    }
                    ''' + decode_function.get_cl_function_name() + '''(
                        ((objective_function_wrapper_data*)data)->data, 
                        x_tmp);
                }
                barrier(CLK_LOCAL_MEM_FENCE);
    
                return ''' + objective_function.get_cl_function_name() + '''(
                    x_tmp, ((objective_function_wrapper_data*)data)->data, objective_list);    
            }
        ''', dependencies=[objective_function, decode_function])
Example #28
0
    def _get_decode_function(self):
        decode_transform = self._weights_codec.get_cl_decode()
        return SimpleCLFunction.from_string('''
            void decodeParameters(void* data, local mot_float_type* x){
                double sum_of_weights = 0;
                for(uint i = 0; i < ''' + str(self._nmr_optimized_weights) + '''; i++){
                    x[i] = ''' + decode_transform.create_assignment('x[i]', 0, 1) + ''';
                    sum_of_weights += x[i];
                }

                for(uint i = 0; i < ''' + str(self._nmr_optimized_weights) + '''; i++){
                    x[i] = x[i] / sum_of_weights;
                }
            }
        ''')
Example #29
0
def get_log_likelihood_function(nmr_observed_tanks):
    return SimpleCLFunction.from_string('''
        double germanTank_logLikelihood(local const mot_float_type* const x, void* data){

            uint nmr_tanks = (uint)round(x[0]);
            double sum = 0;
            double eval;
            for(uint i = 0; i < ''' + str(nmr_observed_tanks) + ''' - 1; i++){
                eval = discrete_uniform(((_model_data*)data)->observed_tanks[i], 1, nmr_tanks);
                sum += eval;
            }
            return sum;
        }
        ''',
                                        dependencies=[discrete_uniform_func()])
Example #30
0
 def _get_numerical_jacobian_func(self, function_name, nmr_params,
                                  nmr_observations):
     return SimpleCLFunction.from_string(r'''
         void compute_jacobian(local mot_float_type* model_parameters,
                               void* data,
                               local mot_float_type* fvec,
                               global mot_float_type* const fjac,
                               local mot_float_type* scratch){
             /**
              * Compute the Jacobian for use in the LM method.
              *
              * This should place the output in the ``fjac`` matrix.
              *
              * Parameters:
              *
              *   model_parameters: (nmr_params,) the current point around which we want to know the Jacobian
              *   data: the current modeling data, used by the objective function
              *   fvec: (nmr_observations,), the current set of function values, corresponding to the given model parameters
              *   fjac: (nmr_parameters, nmr_observations), the memory location for the Jacobian
              *   scratch: (nmr_observations,), temporary storage array for one row of the Jacobian.
              */
             int i, j;
             local mot_float_type temp, step;
             
             mot_float_type EPS = 30 * MOT_EPSILON;
             
             for (j = 0; j < %(NMR_PARAMS)s; j++) {
                 if(get_local_id(0) == 0){
                     temp = model_parameters[j];
                     step = max(EPS*EPS, EPS * fabs(temp));
                     model_parameters[j] += step; /* replace temporarily */
                 }
                 barrier(CLK_LOCAL_MEM_FENCE);
 
                 %(FUNCTION_NAME)s(model_parameters, data, scratch);
 
                 if(get_local_id(0) == 0){
                     for (i = 0; i < %(NMR_OBSERVATIONS)s; i++){
                         fjac[j*%(NMR_OBSERVATIONS)s+i] = (scratch[i] - fvec[i]) / step;
                     }
                     model_parameters[j] = temp; /* restore */
                 }
                 barrier(CLK_LOCAL_MEM_FENCE);
             }
         }
     ''' % dict(FUNCTION_NAME=function_name,
                NMR_PARAMS=nmr_params,
                NMR_OBSERVATIONS=nmr_observations))