You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Jake Mannix (JIRA)" <ji...@apache.org> on 2009/10/29 09:08:59 UTC

[jira] Created: (MATH-313) Functions could be more object-oriented without losing any power.

Functions could be more object-oriented without losing any power.
-----------------------------------------------------------------

                 Key: MATH-313
                 URL: https://issues.apache.org/jira/browse/MATH-313
             Project: Commons Math
          Issue Type: New Feature
    Affects Versions: 2.0
         Environment: all
            Reporter: Jake Mannix
             Fix For: 2.1


UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.

I'd propose we add:

{code}
  UnivariateRealFunction plus(UnivariateRealFunction other);
  UnivariateRealFunction minus(UnivariateRealFunction other);
  UnivariateRealFunction times(UnivariateRealFunction other);
  UnivariateRealFunction times(double scale);
  UnivariateRealFunction preCompose(UnivariateRealFunction other);
  UnivariateRealFunction postCompose(UnivariateRealFunction other);
{code}

to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.

Many people don't need or use this, but... it makes for some powerfully easy code:

{code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}

which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Jake Mannix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12772289#action_12772289 ] 

Jake Mannix commented on MATH-313:
----------------------------------

Regarding practicality of these abstractions, we could limit the scope of "generalized real-valued functions" to instead a set of static building blocks:

{code}
public class Functions {
  
  public abstract class ComposableFunction implements UnivariateRealFunction {
  // has all the methods we described implemented, or maybe shortens "preCompose" to "of" - so you can read it "f of g..." 
  // leaves this abstract:
    abstract double value(double d);
  }

  public static ComposableFunction Exp = new ComposableFunction() { double value(double d) { return Math.exp(d); } }
  public static ComposableFunction Sinh = ...
  
  // lots of java.lang.Math functions here, with object-oriented ways to combine them

  public abstract class BinaryFunction {
    abstract double value(double d1, double d2);
    ComposableFunction fix2ndArg(double secondArg) { /*impl*/ }
    ComposableFunction fix1stArg(double firstArg) { /* impl */ }
  }

  public static BinaryFunction Pow = new BinaryFunction() { double value(double d1, double d2) { return Math.pow(d1, d2); } }
  public static BinaryFunction Log = new BinaryFunction() { double value(double d1, double d2) { return Math.log(d1, d2); } }
  public static BinaryFunction Max = new BinaryFunction() ...
  public static BinaryFunction Min = ... 
}
{code}

This contains the abstraction within one holder class which has a bunch of functional building blocks which are easy to use, and doing things like
{code}
  RealVector w = v.map(Exp.of(Negate.of(Pow.fix2ndArg(2))));
{code}
for when you want to map to a gaussian of your vector.

The use for this kind of thing is pretty varied, but in general allows for some really easy to read and concise stuff, when combined with the Collector paradigm, imagining you have this interface (with the extra collect methods, instead of just one, because for collecting on Vectors, you might imagine the Collector doing something different at different index values - for example, a weighted euclidean dot product, and similarly for matrices):

{code}
public interface UnivariateCollector {
  void collect(double d);
  void collect(int i, double d);
  void collect(int i, int j, double d);
  double result();
}
{code}

This is the interface which gets given to collections of doubles ( like, say, RealVector, and possibly RealMatrix, which already has a visitor, but it's a mutating visitor ), which has the following method and implementation:

{code}
public interface DoubleCollection {
  Iterator<DoubleEntry> iterator();
  Iterator<DoubleEntry> sparseIterator();
  double collect(UnivariateCollector collector);
}
{code}

Note I'm not specifically saying this particular interface should exist in this level of generality, but imagine that these methods are available on AbstractRealVector, at least:

{code}
public abstract class AbstractRealVector implements RealVector, DoubleCollection {

  // leave iterator() and sparseIterator() abstract

  public double collect(UnivariateCollector collector) {
    Iterator<DoubleEntry> it  = // use some logic to decide whether to take sparse or dense iterator
    DoubleEntry e;
    while(it.hasNext() && (e = it.next()) != null) {
      collector.collect(entry.index(), entry.value());
    }
    return collector.result();
  }

// useful for generalized dot products, kernels, distances and angles:
  public double collect(BivariateCollector collector, RealVector v) {
    // use some logic based on whether this or v is instanceof SparseVector, to decide how to iterate both of them, then
    some loop {
      collector.collect(index, thisVectorAtIndex, vAtIndex);
    }
    return collector.result();
  }

  public double normL1() { return collect(Abs.asCollector()); }
  public double normLInf() { return collect(Abs.asCollector(Max)); }
  
 // and in general:
  public double normLp(final double p) { Math.pow(collect(Pow.fix2ndArg(p)).asCollector()), 1/p); }

  public double dot(RealVector v) { return collect(Times.asCollector(), v); }

  public RealVector subtract(RealVector v) { return map(Subtract, v); }

  public RealVector ebeMultiply(RealVector v) { return mapToSelf(Multiply, v); } 
  // ditto for all the other ebeXXX methods

  public double distance(RealVector v) {
    return collect(new AbstractBivariateCollector() {
      public void collect(int index, double d1, double d2) { result += Math.pow(d1-d2, 2); }
    }
  }
  
  // similarly for L1Distance, LInfDistance and in general any Lp distance, and in fact, since Collector knows
  // what index you're on when collecting, it easily deals with weighted distances, and projected onto missing 
  // dimension subspaces in particular
{code}

The reason I bring up these kinds of things is that in Machine Learning, in general, you often want to do fairly arbitrary manipulations on vectors, and you also may want to do arbitrary combinations of them.  I'm primarily interested in vectors and functions from vectors to reals (note: MultivariateRealFunction currently only takes double[] arguments, not RealVector - how to deal with the sparse case, ack!), and vectors to vectors and reals to reals, the the fairly generic sense, and having to write a ton of boilerplate every time I want to compose a function, or write a generalized dot product.  If I can't pass in a function to my vector, I need a method in another class, which doesn't have access to the internals of the vector, which is usually fine, but in general: Vectors should know how to compute their generalized distances, lengths, angles, differences, inner products, etc - given a little guidance on what the specific kind of generalized method they need to use.  

Of course, yes, this can be done fully outside of the linear package: once we have at the very least access to dense + sparse iterators on RealVector, we can write a whole framework outside of linear which has DotProduct (defining double dot(RealVector v1, RealVector v2) ), Distance, KernelizedNorm, etc. This can be done, but doing it this way is not my preference, and dulls my desire to try and help get Commons-Math as the linear library to be used with Mahout and Decomposer.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Luc Maisonobe (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12771647#action_12771647 ] 

Luc Maisonobe commented on MATH-313:
------------------------------------

I strongly disagree with this proposal.
UnivariateRealFunction is a very basic interface and used in many place, for exemple in root solvers.
Almost all uses I have seen for the interface are people declaring their existing class implements it only to be able to use it in a solver. These users class may already belong to a class hierarchy. Java does not support multiple inheritance (which is a good thing), so in many rxisting use cases (in fact all the cases I have seen myself) extending the class would be a real problem.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Resolved: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Luc Maisonobe (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Luc Maisonobe resolved MATH-313.
--------------------------------

    Resolution: Fixed

fixed in subversion repository as of r890002

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Jake Mannix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12771672#action_12771672 ] 

Jake Mannix commented on MATH-313:
----------------------------------

Of course, the easy alternative, if we really want to keep this interface the way it is, is to extend it with an interface like "AlgebraicallyComposableUnivariateRealFunction" (with a better name), which does have an abstract implementation (although we really don't want AbstractAlgebraicallyComposalbeUnivariateRealFunction as a class name!!!), and people can have both choices, and in fact, a concrete impl - DelegatingAlgebraicallyComposableUnivariateRealFunction - could be implemented by taking a UnivariateRealFunction as a constructor arg, and delegates value() to the delegate, and this way you can easily transition between using Functions as genuine objects, and as an interface on your more complex object as well, and you have the best of both worlds.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Jake Mannix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12772262#action_12772262 ] 

Jake Mannix commented on MATH-313:
----------------------------------

Excellent, I can whip up a patch for that sometime this weekend - I think ComposableFunction is closer to real english, that can work.  

Some other things pure function objects can be used for, which I thought might be nice to provide in the abstract implementation is the following: if you have a univariate function, you can produce a MultiVariateRealFunction by applying the input function on each entry of the multivariate case, and then combining the values together, either by default by addition, or by providing a BinaryRealFunction to combine them:

{code}
public interface BinaryRealFunction {
// useful special case of MultivariateRealFunction for two variables
  double value(double d1, double d2);
// a binary real function, when you fix one of the two arguments to be some value, becomes a UnivariateRealFunction
  ComposableFunction fix2ndArgument(double d2);
  ComposableFunction fix1stArgument(double d1);
}
{code}

{code}
public interface ComposableFunction extends UnivariateRealFunction {

    ComposableFunction preCompose(final UnivariateRealFunction f);

    ComposableFunction postCompose(final UnivariateRealFunction f);

/*
 * returns a function implemented as:  combiner.value(this.value(input), f.value(input));
 */
    ComposableFunction combine(final UnivariateRealFunction f, final BinaryRealFunction combiner);

/****
 * common algebraically sensible use cases for the above combine method:
 ****/

    ComposableFunction plus(UnivariateRealFunction f);

    ComposableFunction minus(UnivariateRealFunction f);

    ComposableFunction times(UnivariateRealFunction f);

    ComposableFunction scale(final double scaleFactor);

/*
 * generates a function on double[] inputs as:
 * initialize result = initialValue;
 * then as you iterate: result = combiner.value(result, this.value(nextMultivariateEntry) ); 
 * return result;
 */
  MultivariateRealFunction asCollector(final BinaryRealFunction combiner, final double initialValue);

/*
 * use initialValue as 0 as a simple default:
 */
  MultivariateRealFunction asCollector(final BinaryRealFunction combiner);

/*
 * use Addition as combiner as a simple default:
 */
  MultivariateRealFunction asCollector(final double initialValue);

/*
 * initialValue = 0; combiner = Addition as the most default default
 */
  MultivariateRealFunction asCollector();
}
{code}

Maybe I can just put them all in the same patch with abstract base class definitions which have the full implementation of what I'm talking about, since it's now "non-invasive" as far as the analysis package is concerned, and doesn't affect any other classes, and it could be useful in the implementation of AbstractRealVector, among other places.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Luc Maisonobe (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12772259#action_12772259 ] 

Luc Maisonobe commented on MATH-313:
------------------------------------

This consensus is fine to me.
If you want to provide a patch, I'll be glad to apply it. What about ComposableFunction or CompositableFunction for the name (I don't know which one is real english) ? It could be an interface with an abstract class underneath or simply an abstract class. I agree that not many people would want to provide their own implementation for composition.


> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Luc Maisonobe (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12771681#action_12771681 ] 

Luc Maisonobe commented on MATH-313:
------------------------------------

I'm not aware of people implementing their solver classes, but they implement the function they want to solve. The fact is that in many applications, what users want to find is not the root of an arbitrary mathematical function that can be composed at will. They want to find the root of a function which already has a semantic and despite its free parameter and output value both belong to R in an abstract view, they really belong to different semantic fields, for example a time in seconds for the input and a distance in meters for the output.

I agree with a separate interface extending the existing one.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Jake Mannix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12772090#action_12772090 ] 

Jake Mannix commented on MATH-313:
----------------------------------

Ok, if people are typically out there using commons-math and implementing all the interfaces in the analysis package in classes which have totally separate functionalities and class hierarchies like you're describing (which is what I was questioning whether it happens - I misunderstood you to be talking about the Solvers themselves), then regardless of whether this is good design or not, the interface should be left alone, and can be, even while allowing this functionality for "throwaway functions".

I was thinking of the interface as primarily for lightweight callback-like functions, which are effectively operated _with_, not operated _on_, which is why having the ability to make method calls like:

{code}
RealVector v = w.map(Exp.preCompose(Negate.preCompose(Pow2)));
{code}

as opposed to this

{code}
RealVector v = w.map(new UnivariateRealFunction() {
  public double value(double t) throws FunctionEvaluationException {
    return Exp.value(Negate.value(Pow2.value(t))));
  });
{code}

and instead puts the same boilerplate for composing functions, adding them, subtracting them, multiplying them and scaling them away in an abstract class instead of littering user code.

So like I said - knowing that these interfaces were designed to be used as providing APIs for implementers to toss their own class instances into solvers and other c-math algorithms (which I did not know, just looking at the set of interfaces themselves), it's easy enough to leave the interface alone and make a new one which extends from it which is designed for "pure functions on Real numbers", that really are meant to be nothing *other* than a function.  Maybe that's a better name for this interface: RealPureFunction.  But perhaps it should *only* be an abstract class then, since you don't expect anyone to be implmeneting their own composition methods.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Jake Mannix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12772285#action_12772285 ] 

Jake Mannix commented on MATH-313:
----------------------------------

bq. I agree with Luc on limiting abstract infrastructure to what we have practical use cases for. See "guiding principles" on the home page.

Maybe I misunderstood the uses for this library - when I see classes like "Field<T>" and "FeildElement<T>" in the main o.a.c.math package, I assumed that building in generic mathematical actions is desired as well as simply a toolbox of specific use-cases.

bq. One thing to consider is do we require that Composable functions be total and finite-valued. If not, documenting and debugging NaN/Inf/Exceptions could be tricky for users.

I wondered the same thing: why does UnivariateRealFunction throw a checked exception, forcing users to deal with it on every call?  Could this not be a (specific subclass of) RuntimeException, and let users who need to deal with it deal with it, and other people can ignore it, knowing that they have safe/entire functions, or that they will handle the NaN/Inf cases on their own.

bq. Also, do we require that composition be only "with" ComposableFunctions?

I didn't think that was necessary, no.  The implementation of preCompose, postCompose, plus, minus, times, divide, scale don't require that the argument be ComposableFunction, but they will return an anonymous subclass of ComposableFunction, which has the side benefit of trivially allowing you to turn a non-composable function (Luc's HeatSensor) into a composable one, with ComposableFunction composableHeatSensorFunction = Identity.postCompose(heatSensor);  (this could just as easily be implemented with a delgating function as well, of course).

bq. I guess another thing to think about is inverses.

How would you implement this, in general?

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Phil Steitz (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12772273#action_12772273 ] 

Phil Steitz commented on MATH-313:
----------------------------------

I agree with Luc on limiting abstract infrastructure to what we have practical use cases for.  See "guiding principles" on the home page.  I am +0 on adding ComposableFunction.  One thing to consider is do we require that Composable functions be total and finite-valued.  If not, documenting and debugging NaN/Inf/Exceptions could be tricky for users.  Also, do we require that composition be only "with" ComposableFunctions?  If yes to the second question, you don't need both pre- and postCompose.  I guess another thing to think about is inverses.  I am interested in seeing more on practical use cases for these things.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Luc Maisonobe (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12772263#action_12772263 ] 

Luc Maisonobe commented on MATH-313:
------------------------------------

For now, I'll prefer to avoid BinaryRealFunction until with have a clear use case for it.
Adding layers and layers of pure object oriented features should be done only when really needed. Commons-math try to stay pragmatic. It is a component dedicated to efficient computation not pure theoretical constructs.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Closed: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Phil Steitz (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Phil Steitz closed MATH-313.
----------------------------


> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Jake Mannix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12771651#action_12771651 ] 

Jake Mannix commented on MATH-313:
----------------------------------

At least within Commons-math, nowhere do people have complex classes which implement UnivariateRealFunction, they have static inner classes (or anonymous inner classes) which do the work for them, and I was able to replace all such occurences with AbstractUnivariateRealFunction without much trouble.  I've already got a patch which easily takes care of this throughout all of commons-math.

Are you saying that people outside of commons-math, who are using it, have their solver classes implement a function interface as well?


> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Jake Mannix (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12771695#action_12771695 ] 

Jake Mannix commented on MATH-313:
----------------------------------

I can totally see that many people would not care about composing the function with other functions, but just as many people don't care about doing anything with vectors other than adding them or dot()'ing them doesn't mean that giving them the ability to do so isn't a good thing, right?  From a design perspective, what are the real cases where someone has a class which implements UnivariateRealFunction, but also extends some other class?  You mentioned solvers or root finders, but all the solvers take functions which are passed into them, so they're ok, these could be subclasses of AbstractUnivariateRealFunction very easily.  And even functions which go from one domain to another can be composed with functions which go from the target domain to itself.

But if people really are used to the interface living the way it is, that's fine, in this case (unlike in the RealVector case) it's easy to extend the interface, so I'll draw up a patch to do it in this non-invasive way.

> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (MATH-313) Functions could be more object-oriented without losing any power.

Posted by "Luc Maisonobe (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/MATH-313?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12771957#action_12771957 ] 

Luc Maisonobe commented on MATH-313:
------------------------------------

I guess you didn't get my point so I'll try to be more explicit.
I don't speak about solvers classes, which users almost never extend. I speak about the functions that are solved, which are what the user must implement.
Of course, if a solver accepts an UnivariateRealFunction as parameter it will accept an AbstractUnivariateRealFunction without any change, but it's not the point.

Consider a user with an existing AbstractSensor and a complete classes hierarchy extending this abstract class: OpticalSensor, ContactSensor, HeatSensor, SmellSensor, TelepathicSensor, QuanticSensor, MagicSensor ... One of these derived class, say HeatSensor also implements UnivariateRealFunction because it is used somewhere to find when the heat crosses a desired value:
{code}
public class HeatSensor extends AbstractSensor implements UnivariateRealFunction {

  public double getHeat(double controlValue) {
     // some computation
  }

   public double f(double controlValue) {
      return getHeat(controlValue) - desiredHeat;
   }

}
{code}

The previous code is sufficient to find the controlValue that should be used to get the desired heat by providing an instance of this user class to one of the existing commons-math solvers. This user really doesn't want to implement seven methods when he really needs only one. The contract for the solvers is that the must be able to call f, that's all. HeatSensor cannot extend AbstractUnivariateRealFunction because it already extends AbstractSensor.

There is a big conceptual difference between interfaces that users are almost forced to implement because they will provide instances to commons-math algorithms and interfaces that are rather extension points for which we provide one or a few implementations but want to let users add their own. In the first set, you will find UnivariateRealfunction (analytical), MutationPolicy (genetics), RealMatrixChangingVisitor (linear), FirstOrderDifferentialEquation (ode) ... In the second set you will find RealVector, RealMatrix, ODEIntegrator ...

The interfaces from the first step should remain as simple as possible.

Could you on your side present real use cases for functions composition that could not be handled by a simple:
{code}
UnivariateRealFunction gaussian = new UnivariateRealFunction {
  public double f(double t) {
      return Exp.f((Negate.f(Pow2.f(t))));
  }
}
{code}



> Functions could be more object-oriented without losing any power.
> -----------------------------------------------------------------
>
>                 Key: MATH-313
>                 URL: https://issues.apache.org/jira/browse/MATH-313
>             Project: Commons Math
>          Issue Type: New Feature
>    Affects Versions: 2.0
>         Environment: all
>            Reporter: Jake Mannix
>             Fix For: 2.1
>
>
> UnivariateRealFunction, for example, is a map from R to R.  The set of such functions has tons and tons of structure: in addition to being an algebra, equipped with +,-,*, and scaling by constants, it maps the same space into itself, so it is composable, both pre and post.
> I'd propose we add:
> {code}
>   UnivariateRealFunction plus(UnivariateRealFunction other);
>   UnivariateRealFunction minus(UnivariateRealFunction other);
>   UnivariateRealFunction times(UnivariateRealFunction other);
>   UnivariateRealFunction times(double scale);
>   UnivariateRealFunction preCompose(UnivariateRealFunction other);
>   UnivariateRealFunction postCompose(UnivariateRealFunction other);
> {code}
> to the interface, and then implement them in an AbstractUnivariateRealFunction base class.  No implementer would need to notice, other than switching to extend this class rather than implement UnivariateRealFunction.
> Many people don't need or use this, but... it makes for some powerfully easy code:
> {code}UnivariateRealFunction gaussian = Exp.preCompose(Negate.preCompose(Pow2));{code}
> which is even nicer when done anonymously passing into a map/collect method (a la MATH-312).

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.