1

Can I overload find function in Matlab?

As you know: ind = find(X) locates allnonzero elements of array X, and returns the linear indices ofthose elements in vector ind.

But when X is array of object, how can I use find function to findout elements based on these properties ?

horchler
  • 18,384
  • 4
  • 37
  • 73
Bac Nguyen
  • 21
  • 1
  • do want to use the same function name "FInd"? – backtrack Aug 09 '13 at 04:14
  • I want to use find fuction of matlab to find an object with specify properties. Here is an example of using sort function to sort an array of object. http://www.mathworks.com/matlabcentral/newsreader/view_thread/292163 – Bac Nguyen Aug 09 '13 at 04:22
  • Avoid the confusion and use a new name, like findproperties, or myobjsearch – Peter Aug 09 '13 at 13:36

2 Answers2

3

As Lucius Domitius Ahenobarbus noted in the link he gave, there are strict rules of when you can overload functions in matlab.

Take the following class:

classdef myclass
    methods
        function find(self)
            fprintf('find(myclass) has been called.\n');
        end
    end
end

And execute

X = [myclass myclass myclass]
find(X)

This gives the following output:

X = 

  1x3 myclass with no properties.
  Methods

find(myclass) has been called.

What you do in your overloaded find function is up to you. Just write a function that prints out the indices of the elements that match what you call "these properties", whatever that is.

mars
  • 774
  • 1
  • 13
  • 17
  • Question-> what happens, if you use another find-function within your class? if it is possible to write on without getting an error, which one would be called and would that still overloading or did you just replace the old definition? – Lucius II. Aug 12 '13 at 06:45
  • @LuciusDomitiusAhenobarbus There can only by one `find` method in `myclass`. If I'm not mistaken, when calling `find(foo)`, matlab checks the type of `foo`. If it is a class that has a `find` method, then that gets called. Otherwise the free `find` function gets called. If there are multiple `find` functions in the search path, it picks the first one it finds. So for everything that is not `myclass`, you get the old behaviour. The custom `find` is only called if the first argument is of type `myclass`. Personally I would not overload `find`, but `eq`, `gt` etc and use the standard `find`. – mars Aug 12 '13 at 09:08
  • please have a look at my edited answer. imho, your answer has nothing to do with overloading! you just replace the function find by a class function that is only called, because it is the first one found by function-precedence-order. the Mathworks documentation is wrong or at least misleading from my point of view. you cannot really overload a function in Matlab, if the defintion of overlaoding is as described in my answer... – Lucius II. Aug 12 '13 at 10:04
  • Please, go ahead and type in `a=myclass; b=1:10; find(a); find(b)`. What do you find? Does it print `find(myclass) has been called` once or twice? Did I make the custom find function the dominant one by completely overwriting the built in one? Do you expect `find(a)` to use the more general built in `find` instead of the method? I challenge your definition of overloading. I will use "same name, but different function gets called depending on the arguments". In my experience, what Wikipedia says gives a general idea, but is neither the final authority nor always correct to the last letter. – mars Aug 12 '13 at 11:42
  • +1: point for you and accepted! This indeed fits the definition and you proofed me wrong! But I still want to point out, that this is only possible in very special cases (btw.: is there any other than with class-methods?) – Lucius II. Aug 12 '13 at 12:46
  • @LuciusDomitiusAhenobarbus Thanks. I don't know of any other way except through classes, and that approach only dispatches on the type of the first argument. I guess that is a compromise either for speed or for readability (many matlab users are not programmers and just want their data analyzed instead of learning a complex language). – mars Aug 12 '13 at 15:32
  • 2
    Technical nitpick: Matlab methods may be dispatched either on the type of the first argument, or on the type of any of the arguments, depending on what call syntax is used. For a variable `x`, function name `f`, and other arguments `a`, `b`, and `c`, if you do `x.f(a, b, c)`, then only the type of `x` is considered. But if you use the alternate syntax `f(x, a, b, c)`, then the types of all the inputs are considered, and argument order and `superiorto`/precedence relationships determine which object it's dispatched on. (http://www.mathworks.com/help/matlab/matlab_oop/class-precedence.html) – Andrew Janke Aug 12 '13 at 23:08
2

You can do a couple things here: overload find, or pop out the conditions you want to search on and call the regular find on those. It probably makes more sense to use regular find on a property-access expression.

Property Access Expressions

To apply find to objects or other structures, you can use property access syntax to create logical expressions that identify the objects that meet the conditions you're looking for, and pass those to find. Suppose your class has a qty property, and that's what you're searching on.

ind = find( [X.qty] ~= 0 );

You can combine these logical expressions to do more complicated searches.

ind = find( [X.ghz] > 3 && [X.cacheMB] > 2 && [X.price] < 600 )

Overloading find()

You should probably only overload the well-known Matlab functions like find if your object methods are going to have similar semantics. The find function takes an array of logicals and returns numeric indexes. So it probably only makes sense for your class if the elements of that class could themselves be considered zero or nonzero values in a sense.

To overload a function to work on your class, just define a method in your class with the same name as the function. To work well with other Matlab code, it should probably accept the same typical arguments as the regular function, aside from allowing instances of your object.

Let's say your class represents points in 2-D space as (X,Y) coordinates, and you want to consider the point at the origin (0,0) to be zero, and all other points to be nonzero. You would provide a find method that tests both those points. To make the behavior consistent with Matlab's find, you could just implement the nonzero test in your code, and pass everything else on to the regular find function.

class point
    properties
        X;
        Y;
    end
    methods
        function out = find(obj)
            % Test for zero/nonzero points
            x = reshape([obj.X], size(x));
            y = reshape([obj.Y], size(y));
            isNonzero = x + y; % Quantity is not meaningful, but covers zero/nonzero/NaN
            out = find(isNonzero);
        end
    end
end

To be fully consistent with find, it's a bit more complicated, because find supports additional input and output arguments, which overloaded methods should too.

class point
    properties
        X;
        Y;
    end
    methods
        function varargout = find(obj, varargin)
            varargout = cell(1, max(nargout, 1));
            % TODO: In production code, verify that varargin does not 
            % contain @point objects, to avoid infinite recursion

            % Test for zero/nonzero points
            x = reshape([obj.X], size(obj));
            y = reshape([obj.Y], size(obj));
            isNonzero = x + y; % Quantity is not meaningful, but covers zero/nonzero/NaN

            [varargout{:}] = find(isNonzero, varargin{:});
        end
    end
end

All this is kind of a pain, so you may only want to overload find if you need polymorphic behavior from your objects: that is, if you want to pass them in to other code that is written to call find() on its inputs. If you just need the output of find() locally in your code, it's probably easier to do property access. Or you could just provide an isnonzero() method for quick conversion to an input that find() will play well with.

Andrew Janke
  • 23,508
  • 5
  • 56
  • 85