Bill Allombert on Wed, 27 May 2009 00:09:14 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: Another problem with matrix inversion


On Mon, May 25, 2009 at 10:22:39AM +0200, Lorenz Minder wrote:
> Hi,
> 
> BA:
> > On Thu, May 21, 2009 at 04:43:46AM +0200, Lorenz Minder wrote:
> > > > Sorry for the rushed our reply, but maybe you would prefer it to
> > > > a long delayed one.
> > >
> > > I absolutely do, yes.  Thanks for taking the time.
> > 
> > But I am afraid this lead to misunderstanding. Sorry about that.
> 
> Maybe, and with my rushed reply on your reply, it probably has irritated
> both of us to some degree.  In any case, I apologize form my harsh tone
> in that last mail.
> 
> I still think your "rushed reply" was a good thing, after all it helped
> clear out the non-controversial issues.
> 
> > > I'll look in the test suite, not sure how this works.  (Documentation
> > > is noted, let's talk about this later.)
> > 
> > Test-suite is merely a matter of adding a file src/test/in/foo or
> > expanding an existing file that is not used by 'make bench'.
> 
> Ok.  Is in/linear used by `make bench'?  How do I know?

%make bench|grep linear
* Testing linear        for gp-sta..TIME=20     for gp-dyn..TIME=20

so yes.

> As a tangential issue, when I ran the tests a couple of months ago I
> got a number of failures (Linux on PPC, GMP kernel IIRC), all of which
> were stack overflows.  Should I redo this (with unpatched source) and
> send you guys the results?  (At the time I didn't bother because it
> didn't look like something as serious as wrong output.)

Please do, however I have set up a buildlog on a PlayStation 3 which
does not show any problem currently.

> > > I strongly suggest to go back to the way I did it originally, namely
> > > simply replace FpM_gauss() and Flm_gauss().  Let me quote from the
> > 
> > I have an alternative:
> > 1) We add function FpM_invsafe/Flm_invsafe that would do that same for
> > matrix inversion that Fp_invsafe do for integers. Maybe even
> > FpM_gausssafe if needed.  This is a minimal change, that use a
> > well-defined interface.
> 
> I'm not too sure I get this right.  Fp_invsafe() gives an inverse if it
> exists, so FpM_invsafe would do the same (i.e., it would behave like
> ZnM_gauss(*, NULL, modulus))?  Or do you mean that FpM_invsafe does what
> FpM_gauss() does except err out when p is detected to be nonprime?
> Assuming that it then returns the failing residue class that would be
> useful, of course.

Well the general idea is to rename the current FpM_gauss to FpM_gausssafe,
change it to return the residue (t_INT) if it fails, or the matrix otherwise,
and have a wrapper FpM_gauss that do

GEN
FpM_gauss(GEN a, GEN b, GEN p)
{
  GEN z = FpM_gauss_safe(a,b,p);
  if (typ(z)==t_INT)
    pari_err(invmoder, gmodulo(z,p));
  return z;
}

> I think though that FpM_gausssafe() and Flm_gausssafe() are more
> important than the *_invsafe()-variants.  (Also *_invsafe() is just
> trivial if we have *_gaussafe().)

Agreed.

> > I can do it if you want.
> > 
> > 2) We add a function that take a factored modulus and use chinese
> > remainder and Hensel lifting to use FpM_invsafe to inverse a matrix.
> > Hensel lifting alleviate the need to change FpM_gauss to look for an
> > invertible pivot. This is similar to how gen_Shanks_sqrtn works.
> 
> Ok, so I guess it's the 2nd possibility above, right?
> 
> > 3) We add a function that take an unfactored modulus, call the
> > function above as if the modulus is prime, and if not, refine the
> > factorisation and iterate.
> 
> This sounds reasonable.  The only cost compared to the current solution
> seems to be that Gaussian elimination is restarted from scratch if the
> modulus is proved non-prime.  If that is the case, I think that would
> work just fine. (I don't worry too much about this added cost.)

Well, maybe step 2) could use step 3) for each assumed prime factor to
avoid this issue.

> I'm still not sure how your *safe() proposal would fix the problem with
> the proliferation of new Zn*-routines that the previous approach would
> cause.  Can you elaborate on that?

The idea is that ZnM_inv will defer all linear algebra to FpM_gausssafe,
so there will not need a lot of ZnM function anymore. We will still
need an alias is_ZnM -> is_Fp but that is it. No need for ZlM routine
because FpM_gauss use Flm_gauss internally.

> It's more like a deficiency, then. (-: Yes, I'm joking.)
> 
> > OK, I have made some test and I agree that matadjoint is very slow,
> > even compared to plain RgM_inv without the is_FpM otpimisation.
> 
> I would be interested in the numbers, if you still have them at hand.
> What I noticed is that matdet() (when using slow Gaussian elimination)
> is still usable on a slow machine, when matadjoint(,1) wouldn't work for
> me even on a really fast machine.  (It was very slow, but the worse
> thing was that it would need way too much RAM.)

Well, it is a O(n^4) algorithm instead of O(n^3) so it is not
going to be fast, but I think the problem is that RgX_RgM_eval_i is very
inefficient and waste stack space (we should use Brent&Kung).

> Somewhat unrelatedly, do you have a reference describing the Berkowitz
> algorithm and why it works?

Ask Karim...

> > There is always a cost (in storage/ memory/ testing/ maintainance/
> > consistentcy/ etc.) associate to extra code in PARI. This has to be
> > balanced with use case.
> 
> Yes, and it is not in my interest at all to send you a non-maintainable
> mess.  My understanding of your concern is that the main problem right
> now is that the amount of code may not really warrant the admittedly
> rather rare use case?

Yes, and consistency. It is always annoying to have to draft exception in
the documentation.

> > > > It would be nice if the whole strategy was abstracted to be reused in
> > > > similar
> > > > situation.
> > >
>
> On the other hand, when the modulus is detected to be non-invertible, it
> might possibly be easier to just factor the whole thing instead of doing
> the splitting trick in this case, yes.  (Although it seems to me that
> it would need probably roughly the same amount of code.)

There are other situations than matrix inversion anyway. Some operation
on ideals come to mind.
 
> > > > Do you think there is really a need for 'ZlM' ?  In that range, factoring
> > > > the modulus is trivial, and that would reduce the size of the patch
> > > > somewhat.
> > >
> > > For Flm_gauss() the problem could indeed be solved differently, but
> > > I'm not sure it's so much easier, especially since the case of p having
> > > square factors needs to be considered, and the elimination routines
> > > fixed accordingly in any case.
> > 
> > This is why I suggest to use Hensel lifting.
> 
> Ok, that can be done.
> 
> > PS:
> > Please use Fp_invsafe() (and implement a function Fl_invsafe for the Fl case).
> 
> I can do that. It means an additional duplicate gcd()-call in the
> splitting case; I don't like the look of that too much, but it can be
> done.

Feel free to use invmod() directly instead of Fp_invsafe in FpM_gauss.

> So here is my question:  What should I do to move towards resolving this
> in the best possible way?  Obviously I can get rid of
> find_coprime_factors() and fix the other issues with my last patch, and
> implement the lifting in the m = p^t case, instead of relying on the
> search for a better pivot in FpM_gaussafe().

Start by a patch that implement FpM_gausssafe, and then move on.

> But how is it integrated? I.e., how do I name the functions and where
> can I hook them in?

ZnM_inv sound fine. I will deal with the is_ZnM alias when required.

Cheers,
Bill.