On Thu 2008-10-23 14:54, John Peterson wrote:
> There's no diamond inheritance problem.  See the attached, expanded class 
> graph
> which includes a hypothetical UserShellMatrixBase which is designed to be used
> with both Petsc and Epetra solvers.  It multiply-inherits (an interface only!)
> from NumericMatrix, and it inherits data (no, or minimal, interface!) from 
> both
> PetscMatrixBase and EpetraMatrixBase.  ConcreteUserShell1 and 2 inherit from
> UserShellMatrixBase.  There's no diamond since each of the ConcreteUserShells
> only has one direct line of descent from any one of its given base classes.

Somehow I missed that PetscMatrixBase was really a base, sorry.

> > hyper-diamond inheritance, can you make it possible to use an
> > EpetraMatrix with a PetscSolver (without the user manually wrapping it
> > in a shell matrix)?
> 
> Any user matrix class which inherits from both PetscMatrixBase and
> EpetraMatrixBase will be usable with either of the solvers, since internally,
> it may be dynamic-casted to either type.  I'm not sure support for using
> multiple linear algebra packages simultaneously in LibMesh is perfect, since
> we've never mixed solvers and matrix types before, but I'm confident they 
> could
> all be made to coexist peacefully.

Right, however this is essentially the same thing as my suggestion if
you extend it to its logical end.  Every ${Solver}Matrix would inherit
from every ${Solver}MatrixBase so it could be used as a shell matrix
with that solver (the M:N inheritance).  The code that you suggest would
only go in UserShellMatrixBase can actually wrap an arbitrary
NumericMatrix in a shell matrix of the appropriate type for each solver.
Therefore it's logical that any NumericMatrix can be shell matrix for
any solver at which point we just multiply inherit NumericMatrix (or a
proxy UsefulMatrix) from every *MatrixBase, move the wrapper from
UserShellMatrixBase to NumericMatrix, and we're essentially back at my
solution.  If you want to arbitrarily disallow certain matrix-solver
combinations by making each matrix type decide for itself what solvers
it can be used with, then the hierarchy you propose makes sense to me.
But why would you want to do that?

> >> > The user derives Matrix to implement their shell matrices.
> >>
> >> Right, but I think we already agreed that the interface required by a
> >> shell matrix is a subset of that provided by a full-featured (what we
> >> are now calling) SparseMatrix.  This was the rationale for creating a
> >> new base class, smaller than SparseMatrix, which is easier to derive
> >> from.
> >
> > Oh, I didn't realize that had been agreed upon.  There's no reason why a
> > shell matrix can't implement everything a first-class matrix can.  Many
> > of them won't, but what's the harm in just using not_implemented?  Why
> > arbitrarily cripple shell matrices?
> 
> Primarily because we use the minimal interface to communicate to our
> users what it means to be a NumericMatrix.  When they are all
> "not_implemented" the user is left wondering: "Which of these am I
> *absolutely required* to implement to have a working NumericMatrix?"
> Also, if we find that the NumericMatrix is "crippled" by not having
> enough functionality, we can at a later time move additional
> SparseMatrix interface "up" into the NumericMatrix class, thereby
> making it required of all objects which want to derive from
> NumericMatrix.

Isn't this what documentation is for?  I would say mult() is the only
function which should be required.  This is enough for GMRES so pushing
anything else up would be counter-productive in my opinion.

I still don't see a compelling case for crippling shell matrices.  The
runtime error can easily be informative enough (that's what PETSc will
give you if you try to call an unimplemented operation, usually by
specifying a solver/preconditioner which needs it on the command line).
If you try to distinguish what is implemented at compile time (by
inheritance) then you end up with classes for the power-set of the
operations (in the most general case).  Is it that much nicer to get an
error that a dynamic_cast failed than to get an error that method foo is
not implemented?

> > rather than including petscmat.h, even when PETSc *is* present, so that
> > you don't blast the users namespace with a bunch of implementation that
> > they're never expected to use.  The *interface* is fine with or without
> > PETSc.
> 
> Oh, well the original code which I claimed would need to be ifdef'd out looked
> like this:
> 
> 
>     Mat Matrix::petsc_mat() {
>     Mat mat;
>     MatCreateShell(comm,B.m,B.n,B.M,b.N,(void*)this,&mat);
>     MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))matshell_mult);
>     // set wrappers for any other operations supported by B
>     return mat;
>     }

That won't compile without PETSc, but it's implementation, not
interface.  The interface is stable and user code would not need to be
relinked.

> So there are several function prototypes which would need to exist as well. 
> Supposing it would compile when Petsc is not available, it could produce
> strange runtime results, no?

Hacking the prototypes would be bad design and it snowballs because you
need the MatOperation enum which could change at any time (though the
functions you're likely to use might be stable).

Jed

Attachment: pgpoUhfVtYAiA.pgp
Description: PGP signature

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Libmesh-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libmesh-devel

Reply via email to