You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Phil Steitz <ph...@gmail.com> on 2008/11/30 00:51:25 UTC

[math] Matrix decomposition API

There are a couple of things about the decomposition API that are 
starting to bug me.  Apologies for not having raised them until now, 
since they apply to LU as well as the new Eigen decomp.

1) I don't like the state dependencies bleeding into the decomposition 
interfaces - i.e., having the interface contract include the requirement 
that decompose() be called before the getters.  Logically, the 
decomposition interfaces should just *be* the getters, which is now the 
case for EigenDecomposition, but not LU (where the interface includes 
the decompose method).   The state dependency is an implementation 
artifact that should not be included in the decomposition interface.

2) It would seem natural for decompose return a decomposition, rather 
than void. 

I am not sure if there is an efficient way to address both of these, 
since the caching and incremental computation in the current impls is 
sort of essential.  At a minimum, we should probably remove the 
advertised exceptions and decompose methods from the interfaces.

Here is one idea that may or may not work.  It would make the API a 
little more complicated, but if we split the implementation classes into 
decomposers and decompositions, with decompose producing a 
decomposition, the decompositions would be able to handle state 
transparently to users.

Phil

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [math] Matrix decomposition API

Posted by Phil Steitz <ph...@gmail.com>.
Luc Maisonobe wrote:
> Phil Steitz a écrit :
>   
>> Luc Maisonobe wrote:
>>     
>>> Luc Maisonobe a écrit :
>>>  
>>>       
>>>> Phil Steitz a écrit :
>>>>    
>>>>         
>>>>> There are a couple of things about the decomposition API that are
>>>>> starting to bug me.  Apologies for not having raised them until now,
>>>>> since they apply to LU as well as the new Eigen decomp.
>>>>>
>>>>> 1) I don't like the state dependencies bleeding into the decomposition
>>>>> interfaces - i.e., having the interface contract include the
>>>>> requirement
>>>>> that decompose() be called before the getters.  Logically, the
>>>>> decomposition interfaces should just *be* the getters, which is now the
>>>>> case for EigenDecomposition, but not LU (where the interface includes
>>>>> the decompose method).   The state dependency is an implementation
>>>>> artifact that should not be included in the decomposition interface.
>>>>>
>>>>> 2) It would seem natural for decompose return a decomposition, rather
>>>>> than void.
>>>>> I am not sure if there is an efficient way to address both of these,
>>>>> since the caching and incremental computation in the current impls is
>>>>> sort of essential.  At a minimum, we should probably remove the
>>>>> advertised exceptions and decompose methods from the interfaces.
>>>>>
>>>>> Here is one idea that may or may not work.  It would make the API a
>>>>> little more complicated, but if we split the implementation classes
>>>>> into
>>>>> decomposers and decompositions, with decompose producing a
>>>>> decomposition, the decompositions would be able to handle state
>>>>> transparently to users.
>>>>>       
>>>>>           
>>>> I will try to introduce this.
>>>>     
>>>>         
>>> A few more thoughts. If I understand correctly, you propose is to
>>> separate the decomposition part in an interface with a decompose method
>>> and the solver part as the interface returned by this decompose method.
>>> We would have two parallel hierarchies of interfaces/classes:
>>>
>>> interface DecompositionEngine {
>>>   public DecompositionSolver decompose(RealMatrix);
>>> }
>>>
>>> interface XYZEngine extends DecompositionEngine {
>>>
>>>   public void setThreshold(final double threshold) {
>>>      this.threshold = threshold;
>>>   }
>>>
>>>   public XYZDecomposition xyzDecompose(RealMatrix matrix) {
>>>     XYZDecomposition decomposition = new XYZDecompositionImpl();
>>>     decomposition.setThreshold(threshold);
>>>     decomposition.doWhatYouWantWithMatrix(matrix);
>>>     return decomposition;
>>>   }
>>>
>>>   public DecompositionSolver decompose(RealMatrix matrix) {
>>>     return xyzDecompose(matrix);
>>>   }
>>>
>>> }
>>>
>>> interface DecompositionSolver {
>>>   public RealVector solve(RealVector);
>>> }
>>>
>>> interface XYZDecomposition extends DecompositionSolver {
>>>   public void setThreshold(double threshold);
>>>   public RealMatrix getX();
>>>   public RealMatrix getY();
>>>   public RealMatrix getZ();
>>> }
>>>
>>> class XYZDecompositionImpl() implements XYZDecomposition {
>>> }
>>>
>>> This allows both dedicated use of a specific algorithm (XYZ) and the
>>> extra methods it provides (setThrehold, getX ...) and use of generic
>>> interfaces (DecompositionEngine, DecompositionSolver) and the generic
>>> methods (solve, getInverse ...). It is however quite complex.
>>>
>>> A simpler approach is to remove the umbrella interface
>>> DecompositionEngine and the generic decompose method and retain
>>> everything else (perhaps reusing the single name "decompose" for the now
>>> independent methods with different return types). The
>>> DecompositionSolver interface would be kept. This prevents use of a
>>> generic engine.
>>>
>>> An even simpler approach would be to completely remove the state
>>> dependencies part by removing the decompose method and forcing
>>> everything to be set up right at construction. I'm not sure you would
>>> consider it addresses your second point.
>>>
>>> Luc
>>>   
>>>       
>> Sorry I was not clear.  What I meant was to split things more along the
>> following lines (assuming this can be made to work), for e.g.
>> EigenDecompostion.
>>
>> 1. Keep EigenDecomposition as is, but make it standalone - i.e., drop
>> the "Extends DecompositionSolver".  So this now just represents a
>> decomposition.
>>
>> 2. Leave the decompose method in a DecompositionEngine or somesuch with
>> signature
>> EigenDecomposition decompose(RealMatrix).  Leave solve there or put in a
>> separate solver class with signature
>> double[] solve(double[] b, EigenDecomposition ed)
>>
>> So you use decompose(RealMatrix) do create a decomposition that can be
>> used directly or passed to a solver.    This gets around the state
>> dependencies and the need to have constructors do the decompositions. 
>> The DecompositionEngine's decompose method could return a
>> DecompositionImpl that handles state / incremental computation
>> transparently to users.
>>     
>
> I have implemented this. I agree the separation between decomposition
> and solve was worth the change. Could you have a look to the new API ?
>
> Luc
>
>   
Looks good.  Just one last question / suggestion.   In the 
DecompositionSolver, why to we keep the argumentless decompose() methods 
and the matrix as an instance variable?  The argumentless methods just 
delegate to the ones that take a matrix as an argument and the instance 
variable is otherwise unused. 

Phil
>> Phil
>>
>>     
>>>  
>>>       
>>>> Thanks for the advice.
>>>> Luc
>>>>
>>>>    
>>>>         
>>>>> Phil
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>>>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>>>
>>>>>
>>>>>       
>>>>>           
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>>
>>>>
>>>>     
>>>>         
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>
>>>   
>>>       
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> For additional commands, e-mail: dev-help@commons.apache.org
>>
>>
>>     
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
>
>   


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [math] Matrix decomposition API

Posted by Luc Maisonobe <Lu...@free.fr>.
Phil Steitz a écrit :
> Luc Maisonobe wrote:
>> Luc Maisonobe a écrit :
>>  
>>> Phil Steitz a écrit :
>>>    
>>>> There are a couple of things about the decomposition API that are
>>>> starting to bug me.  Apologies for not having raised them until now,
>>>> since they apply to LU as well as the new Eigen decomp.
>>>>
>>>> 1) I don't like the state dependencies bleeding into the decomposition
>>>> interfaces - i.e., having the interface contract include the
>>>> requirement
>>>> that decompose() be called before the getters.  Logically, the
>>>> decomposition interfaces should just *be* the getters, which is now the
>>>> case for EigenDecomposition, but not LU (where the interface includes
>>>> the decompose method).   The state dependency is an implementation
>>>> artifact that should not be included in the decomposition interface.
>>>>
>>>> 2) It would seem natural for decompose return a decomposition, rather
>>>> than void.
>>>> I am not sure if there is an efficient way to address both of these,
>>>> since the caching and incremental computation in the current impls is
>>>> sort of essential.  At a minimum, we should probably remove the
>>>> advertised exceptions and decompose methods from the interfaces.
>>>>
>>>> Here is one idea that may or may not work.  It would make the API a
>>>> little more complicated, but if we split the implementation classes
>>>> into
>>>> decomposers and decompositions, with decompose producing a
>>>> decomposition, the decompositions would be able to handle state
>>>> transparently to users.
>>>>       
>>> I will try to introduce this.
>>>     
>>
>> A few more thoughts. If I understand correctly, you propose is to
>> separate the decomposition part in an interface with a decompose method
>> and the solver part as the interface returned by this decompose method.
>> We would have two parallel hierarchies of interfaces/classes:
>>
>> interface DecompositionEngine {
>>   public DecompositionSolver decompose(RealMatrix);
>> }
>>
>> interface XYZEngine extends DecompositionEngine {
>>
>>   public void setThreshold(final double threshold) {
>>      this.threshold = threshold;
>>   }
>>
>>   public XYZDecomposition xyzDecompose(RealMatrix matrix) {
>>     XYZDecomposition decomposition = new XYZDecompositionImpl();
>>     decomposition.setThreshold(threshold);
>>     decomposition.doWhatYouWantWithMatrix(matrix);
>>     return decomposition;
>>   }
>>
>>   public DecompositionSolver decompose(RealMatrix matrix) {
>>     return xyzDecompose(matrix);
>>   }
>>
>> }
>>
>> interface DecompositionSolver {
>>   public RealVector solve(RealVector);
>> }
>>
>> interface XYZDecomposition extends DecompositionSolver {
>>   public void setThreshold(double threshold);
>>   public RealMatrix getX();
>>   public RealMatrix getY();
>>   public RealMatrix getZ();
>> }
>>
>> class XYZDecompositionImpl() implements XYZDecomposition {
>> }
>>
>> This allows both dedicated use of a specific algorithm (XYZ) and the
>> extra methods it provides (setThrehold, getX ...) and use of generic
>> interfaces (DecompositionEngine, DecompositionSolver) and the generic
>> methods (solve, getInverse ...). It is however quite complex.
>>
>> A simpler approach is to remove the umbrella interface
>> DecompositionEngine and the generic decompose method and retain
>> everything else (perhaps reusing the single name "decompose" for the now
>> independent methods with different return types). The
>> DecompositionSolver interface would be kept. This prevents use of a
>> generic engine.
>>
>> An even simpler approach would be to completely remove the state
>> dependencies part by removing the decompose method and forcing
>> everything to be set up right at construction. I'm not sure you would
>> consider it addresses your second point.
>>
>> Luc
>>   
> 
> Sorry I was not clear.  What I meant was to split things more along the
> following lines (assuming this can be made to work), for e.g.
> EigenDecompostion.
> 
> 1. Keep EigenDecomposition as is, but make it standalone - i.e., drop
> the "Extends DecompositionSolver".  So this now just represents a
> decomposition.
> 
> 2. Leave the decompose method in a DecompositionEngine or somesuch with
> signature
> EigenDecomposition decompose(RealMatrix).  Leave solve there or put in a
> separate solver class with signature
> double[] solve(double[] b, EigenDecomposition ed)
> 
> So you use decompose(RealMatrix) do create a decomposition that can be
> used directly or passed to a solver.    This gets around the state
> dependencies and the need to have constructors do the decompositions. 
> The DecompositionEngine's decompose method could return a
> DecompositionImpl that handles state / incremental computation
> transparently to users.

I have implemented this. I agree the separation between decomposition
and solve was worth the change. Could you have a look to the new API ?

Luc

> 
> Phil
> 
>>  
>>> Thanks for the advice.
>>> Luc
>>>
>>>    
>>>> Phil
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>>
>>>>
>>>>       
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>
>>>
>>>     
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> For additional commands, e-mail: dev-help@commons.apache.org
>>
>>   
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [math] Matrix decomposition API

Posted by Phil Steitz <ph...@gmail.com>.
Luc Maisonobe wrote:
> Luc Maisonobe a écrit :
>   
>> Phil Steitz a écrit :
>>     
>>> There are a couple of things about the decomposition API that are
>>> starting to bug me.  Apologies for not having raised them until now,
>>> since they apply to LU as well as the new Eigen decomp.
>>>
>>> 1) I don't like the state dependencies bleeding into the decomposition
>>> interfaces - i.e., having the interface contract include the requirement
>>> that decompose() be called before the getters.  Logically, the
>>> decomposition interfaces should just *be* the getters, which is now the
>>> case for EigenDecomposition, but not LU (where the interface includes
>>> the decompose method).   The state dependency is an implementation
>>> artifact that should not be included in the decomposition interface.
>>>
>>> 2) It would seem natural for decompose return a decomposition, rather
>>> than void.
>>> I am not sure if there is an efficient way to address both of these,
>>> since the caching and incremental computation in the current impls is
>>> sort of essential.  At a minimum, we should probably remove the
>>> advertised exceptions and decompose methods from the interfaces.
>>>
>>> Here is one idea that may or may not work.  It would make the API a
>>> little more complicated, but if we split the implementation classes into
>>> decomposers and decompositions, with decompose producing a
>>> decomposition, the decompositions would be able to handle state
>>> transparently to users.
>>>       
>> I will try to introduce this.
>>     
>
> A few more thoughts. If I understand correctly, you propose is to
> separate the decomposition part in an interface with a decompose method
> and the solver part as the interface returned by this decompose method.
> We would have two parallel hierarchies of interfaces/classes:
>
> interface DecompositionEngine {
>   public DecompositionSolver decompose(RealMatrix);
> }
>
> interface XYZEngine extends DecompositionEngine {
>
>   public void setThreshold(final double threshold) {
>      this.threshold = threshold;
>   }
>
>   public XYZDecomposition xyzDecompose(RealMatrix matrix) {
>     XYZDecomposition decomposition = new XYZDecompositionImpl();
>     decomposition.setThreshold(threshold);
>     decomposition.doWhatYouWantWithMatrix(matrix);
>     return decomposition;
>   }
>
>   public DecompositionSolver decompose(RealMatrix matrix) {
>     return xyzDecompose(matrix);
>   }
>
> }
>
> interface DecompositionSolver {
>   public RealVector solve(RealVector);
> }
>
> interface XYZDecomposition extends DecompositionSolver {
>   public void setThreshold(double threshold);
>   public RealMatrix getX();
>   public RealMatrix getY();
>   public RealMatrix getZ();
> }
>
> class XYZDecompositionImpl() implements XYZDecomposition {
> }
>
> This allows both dedicated use of a specific algorithm (XYZ) and the
> extra methods it provides (setThrehold, getX ...) and use of generic
> interfaces (DecompositionEngine, DecompositionSolver) and the generic
> methods (solve, getInverse ...). It is however quite complex.
>
> A simpler approach is to remove the umbrella interface
> DecompositionEngine and the generic decompose method and retain
> everything else (perhaps reusing the single name "decompose" for the now
> independent methods with different return types). The
> DecompositionSolver interface would be kept. This prevents use of a
> generic engine.
>
> An even simpler approach would be to completely remove the state
> dependencies part by removing the decompose method and forcing
> everything to be set up right at construction. I'm not sure you would
> consider it addresses your second point.
>
> Luc
>   

Sorry I was not clear.  What I meant was to split things more along the 
following lines (assuming this can be made to work), for e.g. 
EigenDecompostion.

1. Keep EigenDecomposition as is, but make it standalone - i.e., drop 
the "Extends DecompositionSolver".  So this now just represents a 
decomposition.

2. Leave the decompose method in a DecompositionEngine or somesuch with 
signature
EigenDecomposition decompose(RealMatrix).  Leave solve there or put in a 
separate solver class with signature
double[] solve(double[] b, EigenDecomposition ed)

So you use decompose(RealMatrix) do create a decomposition that can be 
used directly or passed to a solver.    This gets around the state 
dependencies and the need to have constructors do the decompositions.  
The DecompositionEngine's decompose method could return a 
DecompositionImpl that handles state / incremental computation 
transparently to users.

Phil

>   
>> Thanks for the advice.
>> Luc
>>
>>     
>>> Phil
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>
>>>
>>>       
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> For additional commands, e-mail: dev-help@commons.apache.org
>>
>>
>>     
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
>
>   


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [math] Matrix decomposition API

Posted by Luc Maisonobe <Lu...@free.fr>.
Luc Maisonobe a écrit :
> Phil Steitz a écrit :
>> There are a couple of things about the decomposition API that are
>> starting to bug me.  Apologies for not having raised them until now,
>> since they apply to LU as well as the new Eigen decomp.
>>
>> 1) I don't like the state dependencies bleeding into the decomposition
>> interfaces - i.e., having the interface contract include the requirement
>> that decompose() be called before the getters.  Logically, the
>> decomposition interfaces should just *be* the getters, which is now the
>> case for EigenDecomposition, but not LU (where the interface includes
>> the decompose method).   The state dependency is an implementation
>> artifact that should not be included in the decomposition interface.
>>
>> 2) It would seem natural for decompose return a decomposition, rather
>> than void.
>> I am not sure if there is an efficient way to address both of these,
>> since the caching and incremental computation in the current impls is
>> sort of essential.  At a minimum, we should probably remove the
>> advertised exceptions and decompose methods from the interfaces.
>>
>> Here is one idea that may or may not work.  It would make the API a
>> little more complicated, but if we split the implementation classes into
>> decomposers and decompositions, with decompose producing a
>> decomposition, the decompositions would be able to handle state
>> transparently to users.
> 
> I will try to introduce this.

A few more thoughts. If I understand correctly, you propose is to
separate the decomposition part in an interface with a decompose method
and the solver part as the interface returned by this decompose method.
We would have two parallel hierarchies of interfaces/classes:

interface DecompositionEngine {
  public DecompositionSolver decompose(RealMatrix);
}

interface XYZEngine extends DecompositionEngine {

  public void setThreshold(final double threshold) {
     this.threshold = threshold;
  }

  public XYZDecomposition xyzDecompose(RealMatrix matrix) {
    XYZDecomposition decomposition = new XYZDecompositionImpl();
    decomposition.setThreshold(threshold);
    decomposition.doWhatYouWantWithMatrix(matrix);
    return decomposition;
  }

  public DecompositionSolver decompose(RealMatrix matrix) {
    return xyzDecompose(matrix);
  }

}

interface DecompositionSolver {
  public RealVector solve(RealVector);
}

interface XYZDecomposition extends DecompositionSolver {
  public void setThreshold(double threshold);
  public RealMatrix getX();
  public RealMatrix getY();
  public RealMatrix getZ();
}

class XYZDecompositionImpl() implements XYZDecomposition {
}

This allows both dedicated use of a specific algorithm (XYZ) and the
extra methods it provides (setThrehold, getX ...) and use of generic
interfaces (DecompositionEngine, DecompositionSolver) and the generic
methods (solve, getInverse ...). It is however quite complex.

A simpler approach is to remove the umbrella interface
DecompositionEngine and the generic decompose method and retain
everything else (perhaps reusing the single name "decompose" for the now
independent methods with different return types). The
DecompositionSolver interface would be kept. This prevents use of a
generic engine.

An even simpler approach would be to completely remove the state
dependencies part by removing the decompose method and forcing
everything to be set up right at construction. I'm not sure you would
consider it addresses your second point.

Luc

> Thanks for the advice.
> Luc
> 
>> Phil
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> For additional commands, e-mail: dev-help@commons.apache.org
>>
>>
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Re: [math] Matrix decomposition API

Posted by Luc Maisonobe <Lu...@free.fr>.
Phil Steitz a écrit :
> There are a couple of things about the decomposition API that are
> starting to bug me.  Apologies for not having raised them until now,
> since they apply to LU as well as the new Eigen decomp.
> 
> 1) I don't like the state dependencies bleeding into the decomposition
> interfaces - i.e., having the interface contract include the requirement
> that decompose() be called before the getters.  Logically, the
> decomposition interfaces should just *be* the getters, which is now the
> case for EigenDecomposition, but not LU (where the interface includes
> the decompose method).   The state dependency is an implementation
> artifact that should not be included in the decomposition interface.
> 
> 2) It would seem natural for decompose return a decomposition, rather
> than void.
> I am not sure if there is an efficient way to address both of these,
> since the caching and incremental computation in the current impls is
> sort of essential.  At a minimum, we should probably remove the
> advertised exceptions and decompose methods from the interfaces.
> 
> Here is one idea that may or may not work.  It would make the API a
> little more complicated, but if we split the implementation classes into
> decomposers and decompositions, with decompose producing a
> decomposition, the decompositions would be able to handle state
> transparently to users.

I will try to introduce this.
Thanks for the advice.
Luc

> 
> Phil
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org