function stopfun = stopifdeletedfile(filename)
% Create an interactive stopping criterion based on the existence of a file
%
% function stopfun = stopifdeletedfile()
% function stopfun = stopifdeletedfile(filename)
%
% Use on the options structure passed to a Manopt solver, e.g.:
%
%   problem = ... % manopt problem structure with manifold, cost function, ...
%   options.stopfun = stopifdeletedfile(); % add this option
%   trustregions(problem, x0, options); % run this or any other solver
%
% This will create a temporary file called MANOPT_DELETE_ME_TO_STOP_SOLVER
% in the present working directory. If this file is deleted at any time
% during the solver's execution, the solver will terminate gracefully and
% return its current iterate as soon as it gets to the point of evaluating
% stopping criteria. A different file name can also be specified using the
% input string filename (optional).
%
% Note: certain solvers (including trustregions) check stopping criteria
% only at outer iterations, not during inner iterations; hence, their may
% be a delay before actual termination.
%
% See also: statsfunhelper stopifclosedfigure

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

    % Default name for the temporary file.
    if ~exist('filename', 'var') || isempty(filename)
        filename = 'MANOPT_DELETE_ME_TO_STOP_SOLVER';
    end

    % Make sure the file exists, and release our handle on it.
    fid = fopen(filename, 'a');
    if fid >= 0
        fclose(fid);    
        % The stopping criterion is a function handle.
        stopfun = @checkcriterion;
    else
        warning('manopt:stopifdeletedfile', ...
              'Couldn''t create the file: no stopping criterion created.');
        stopfun = @(problem, x, info, last) false;
    end


    % The function is defined as a subfunction so that it has access to
    % filename without the need for an @() construct. This makes it easier
    % for Matlab to determine the number of output arguments of the
    % function handle @checkcriterion, which ultimately helps
    % stoppingcriterion determine how to call it.
    function [stop, reason] = checkcriterion(problem, x, info, last) %#ok<INUSD>

        reason = sprintf(['Interactive stopping criterion ' ...
                     '(file %s deleted). See options.stopfun.'], filename);

        % Try to access the file.
        fid = fopen(filename, 'r');

        % If we can't, it means the file no longer exists: stop the solver.
        % Otherwise, release our handle on the file to make sure it can be
        % deleted by another program.
        if fid < 0
            stop = true;
        else
            fclose(fid);
            stop = false;
        end

    end
    
end
