
classdef (Sealed = true) odeMassMatrix
    properties
        MassMatrix % Mass matrix [ constant matrix | function_handle ]
        Singular(1,1) matlab.ode.Singular % Mass matrix is singular  [ yes | no | {maybe} ]
        StateDependence(1,1) matlab.ode.StateDependence % Dependence of the mass matrix on y [ none | {weak} | strong ]
        SparsityPattern % dM/dy sparsity pattern [ sparse matrix ]
    end
    methods
        function obj = odeMassMatrix(nv)
            arguments
                nv.MassMatrix
                nv.StateDependence(1,1) matlab.ode.StateDependence
                nv.Singular(1,1) matlab.ode.Singular
                nv.SparsityPattern
            end
            % Apply defaults without losing the ability to determine
            % whether they were supplied by the user.
            obj.StateDependence = matlab.ode.StateDependence.weak;
            obj.Singular = matlab.ode.Singular.maybe;
            % Assign values according to inputs.
            names = fieldnames(nv);
            for k = 1:numel(names)
                obj.(names{k}) = nv.(names{k});
            end
            if isfield(nv,"MassMatrix")
                if isnumeric(obj.MassMatrix)
                    if ~isfield(nv,"StateDependence")
                        obj.StateDependence = matlab.ode.StateDependence.none;
                    end
                    if ~isfield(nv,"Singular") && isfloat(obj.MassMatrix)
                        if issparse(obj.MassMatrix)
                            nz = nnz(obj.MassMatrix);
                            % Use double precision eps because sparse is
                            % only double or logical.
                            isSingular = nz*eps*condest(obj.MassMatrix) > 1;
                        else
                            isSingular = rank(obj.MassMatrix) < size(obj.MassMatrix,2);
                        end
                        if isSingular
                            obj.Singular = matlab.ode.Singular.yes;
                        else
                            obj.Singular = matlab.ode.Singular.no;
                        end
                    end
                elseif ~isfield(nv,"StateDependence") && nargin(obj.MassMatrix) <= 1 
                    obj.StateDependence = matlab.ode.StateDependence.none;
                end
            end
        end
        function obj = set.MassMatrix(obj,M)
            if isa(M,'function_handle') || isnumeric(M)
                obj.MassMatrix = M;
            else
                error(message("MATLAB:ode:InvalidMassMatrix"));
            end
        end
    end

    properties(Constant,Hidden)
        % 1.0 : Initial version (R2023b)
        Version = 1.0;
    end

    methods (Hidden)
        function b = saveobj(a)
            % Save all properties to struct. 
            b = ode.assignProps(a,false,"odeMassMatrix");
            % Keep track of versioning information.
            b.CompatibilityHelper.versionSavedFrom = a.Version;
            b.CompatibilityHelper.minCompatibleVersion = 1.0;
        end
    end

    methods (Hidden,Static)
        function b = loadobj(a)
            if odeMassMatrix.Version < a.CompatibilityHelper.minCompatibleVersion
                warning(message("MATLAB:ode:MinVersionIncompat","odeMassMatrix"));
                b = odeMassMatrix;
                return
            end
            b = ode.assignProps(a,true,"odeMassMatrix");
        end
    end

end

%    Copyright 2023 MathWorks, Inc.