function [x, cost, info, options] = manoptsolve(problem, x0, options)
% Gateway helper function to call a Manopt solver, chosen in the options.
%
% function [x, cost, info, options] = manoptsolve(problem)
% function [x, cost, info, options] = manoptsolve(problem, x0)
% function [x, cost, info, options] = manoptsolve(problem, x0, options)
% function [x, cost, info, options] = manoptsolve(problem, [], options)
%
% Depending on what is available in the Manopt problem structure, one of
% the Manopt solvers will be called and the outputs passed along. It is
% also possible to force the choice of a solver by specifying it in the
% options structure. For example:
%
%    options.solver = @trustregions;
%
% Simply specify a function handle to a Manopt solver.
%
% See also: trustregions conjugategradient steepestdescent

% This file is part of Manopt: www.manopt.org.
% Original author: Nicolas Boumal, Aug. 13, 2014.
% Contributors: 
% Change log: 

    % At the very least, we need a cost function.
    if ~canGetCost(problem)
        error('The problem structure must specify a cost function.');
    end
    
    % Depending on the number of differentials available, pick a different
    % default solver.
    if ~canGetGradient(problem)
        localdefaults.solver = @neldermead;
    elseif ~canGetHessian(problem)
        localdefaults.solver = @conjugategradient;
    else
        localdefaults.solver = @trustregions;
    end
    
    % Merge local defaults with user options, if any.
    if ~exist('options', 'var') || isempty(options)
        options = struct();
    end
    options = mergeOptions(localdefaults, options);
    
    % If no initial guess was specified, prepare the empty one.
    if ~exist('x0', 'var')
        x0 = [];
    end
    
    % Issue the actual call.
    [x, cost, info, options] = options.solver(problem, x0, options);
    
end
