source: git/Singular/dyn_modules/syzextra/syzextra.h @ db7f1f

spielwiese
Last change on this file since db7f1f was db7f1f, checked in by Hans Schoenemann <hannes@…>, 17 months ago
simplify syzextra
  • Property mode set to 100644
File size: 15.0 KB
Line 
1// -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2/*****************************************************************************\
3 * Computer Algebra System SINGULAR
4\*****************************************************************************/
5/** @file syzextra.h
6 *
7 * Computation of Syzygies
8 *
9 * ABSTRACT: Computation of Syzygies due to Schreyer
10 *
11 * @author Oleksandr Motsak
12 *
13 **/
14/*****************************************************************************/
15
16#ifndef SYZEXTRA_H
17#define SYZEXTRA_H
18
19#include <vector>
20#include <map>
21#include <string.h>
22#include <stack>
23
24// include basic definitions
25#include "singularxx_defs.h"
26#include "kernel/ideals.h"
27
28class idrec; typedef idrec *   idhdl;
29
30class kBucket; typedef kBucket* kBucket_pt;
31
32#ifndef NOPRODUCT
33# define NOPRODUCT 1
34#endif
35
36// set to 1 if all leading coeffs are assumed to be all =1...
37// note the use of simplify on input in SSinit!
38#ifndef NODIVISION
39# define NODIVISION 1
40#endif
41
42poly leadmonom(const poly p, const ring r, const bool bSetZeroComp = true);
43
44/// inplace sorting of the module (ideal) id wrt <_(c,ds)
45void Sort_c_ds(const ideal id, const ring r);
46
47
48class sBucket; typedef sBucket* sBucket_pt;
49
50/** @class SBucketFactory syzextra.h
51 *
52 * sBucket Factory
53 *
54 * Cleate/store/reuse buckets
55 *
56 */
57class SBucketFactory: private std::stack <sBucket_pt>
58{
59  private:
60    typedef std::stack <sBucket_pt> Base;
61
62  public:
63    typedef Base::value_type Bucket;
64
65    SBucketFactory(const ring r)
66    {
67      push ( _CreateBucket(r) ); // start with at least one sBucket...?
68      assume( top() != NULL );
69    };
70
71    ~SBucketFactory()
72    {
73      while( !empty() )
74      {
75        _DestroyBucket( top() );
76        pop();
77      }
78    }
79
80    Bucket getBucket(const ring r, const bool remove = true)
81    {
82      Bucket bt = NULL;
83
84      if( !empty() )
85      {
86        bt = top();
87
88        if( remove )
89          pop();
90      }
91      else
92      {
93        bt = _CreateBucket(r);
94
95        if( !remove )
96        {
97          push(bt);
98          assume( bt == top() );
99        }
100      }
101
102      assume( bt != NULL );
103
104      return bt;
105    }
106
107    // TODO: this may be spared if we give-out a smart Bucket (which returns here upon its destructor!)
108    void putBucket(const Bucket & bt, const bool replace = false)
109    {
110      assume( bt != NULL );
111
112      if( empty() )
113        push( bt );
114      else
115      {
116        if( replace )
117          top() = bt;
118        else
119        {
120          if( bt != top() )
121            push( bt );
122        }
123      }
124
125      assume( bt == top() );
126    }
127
128  private:
129    /// inital allocation for new buckets
130    static Bucket _CreateBucket(const ring r);
131
132    /// we only expect empty buckets to be left at the end for destructor
133    /// bt will be set to NULL
134    static void _DestroyBucket(Bucket & bt);
135
136  private:
137    SBucketFactory();
138    SBucketFactory(const SBucketFactory&);
139    void operator=(const SBucketFactory&);
140
141};
142
143/// Computation attribute storage
144struct SchreyerSyzygyComputationFlags
145{
146    SchreyerSyzygyComputationFlags(idhdl rootRingHdl);
147
148    SchreyerSyzygyComputationFlags(const SchreyerSyzygyComputationFlags& attr):
149        OPT__DEBUG(attr.OPT__DEBUG),
150        OPT__LEAD2SYZ(attr.OPT__LEAD2SYZ),  OPT__TAILREDSYZ(attr.OPT__TAILREDSYZ),
151        OPT__HYBRIDNF(attr.OPT__HYBRIDNF), OPT__IGNORETAILS(attr.OPT__IGNORETAILS),
152        OPT__SYZNUMBER(attr.OPT__SYZNUMBER), OPT__TREEOUTPUT(attr.OPT__TREEOUTPUT),
153        OPT__SYZCHECK(attr.OPT__SYZCHECK), OPT__PROT(attr.OPT__PROT),
154        OPT__NOCACHING(attr.OPT__NOCACHING),
155        m_rBaseRing(attr.m_rBaseRing)
156    {}
157
158  /// output all the intermediate states
159  const int OPT__DEBUG; // DebugOutput;
160
161  /// ?
162  const int OPT__LEAD2SYZ; // TwoLeadingSyzygyTerms;
163
164  /// Reduce syzygy tails wrt the leading syzygy terms
165  const int OPT__TAILREDSYZ; // TailReducedSyzygies;
166
167  /// Use the usual NF's S-poly reduction while dropping lower order terms
168  /// 2 means - smart selection!
169  const int OPT__HYBRIDNF; // UseHybridNF
170
171
172  /// ignore tails and compute the pure Schreyer frame
173  const int OPT__IGNORETAILS; // @IGNORETAILS
174
175  /// Syzygy level (within a resolution)
176  mutable int OPT__SYZNUMBER;
177
178  inline void  nextSyzygyLayer() const
179  {
180     OPT__SYZNUMBER++;
181  }
182
183  /// output lifting tree
184  const int OPT__TREEOUTPUT;
185
186  /// CheckSyzygyProperty: TODO
187  const int OPT__SYZCHECK;
188
189  /// TEST_OPT_PROT
190  const bool OPT__PROT;
191
192  /// no caching/stores/lookups
193  const int OPT__NOCACHING;
194
195  /// global base ring
196  const ring m_rBaseRing;
197};
198
199class SchreyerSyzygyComputation;
200
201class CLCM: public SchreyerSyzygyComputationFlags, public std::vector<bool>
202{
203  public:
204    CLCM(const ideal& L, const SchreyerSyzygyComputationFlags& flags);
205
206    bool Check(const poly m) const;
207
208  private:
209    bool m_compute;
210
211    const unsigned int m_N; ///< number of ring variables
212};
213
214
215class CLeadingTerm
216{
217  public:
218    CLeadingTerm(unsigned int label,  const poly lt, const ring);
219
220#if NOPRODUCT
221    bool DivisibilityCheck(const poly multiplier, const poly t, const unsigned long not_sev, const ring r) const;
222#endif
223    bool DivisibilityCheck(const poly product, const unsigned long not_sev, const ring r) const;
224
225    bool CheckLT( const ideal & L ) const;
226
227    inline poly lt() const { return m_lt; };
228    inline unsigned long sev() const { return m_sev; };
229    inline unsigned int label() const { return m_label; };
230  private:
231    const unsigned long m_sev; ///< not short exp. vector
232
233    // NOTE/TODO: either of the following should be enough:
234    const unsigned int  m_label; ///< index in the main L[] + 1
235
236    const poly          m_lt; ///< the leading term itself L[label-1]
237
238    // disable the following:
239    CLeadingTerm();
240    CLeadingTerm(const CLeadingTerm&);
241    void operator=(const CLeadingTerm&);
242};
243
244
245// TODO: needs a specialized variant without a component (hash!)
246class CReducerFinder: public SchreyerSyzygyComputationFlags
247{
248#if NOPRODUCT
249  friend class CDivisorEnumerator2;
250#endif
251  friend class CDivisorEnumerator;
252
253  public:
254    typedef long TComponentKey;
255    typedef std::vector<const CLeadingTerm*> TReducers;
256
257  private:
258    typedef std::map< TComponentKey, TReducers> CReducersHash;
259
260  public:
261    /// goes over all leading terms
262    CReducerFinder(const ideal L, const SchreyerSyzygyComputationFlags& flags);
263
264    void Initialize(const ideal L);
265
266    ~CReducerFinder();
267
268
269#if NOPRODUCT
270    poly
271        FindReducer(const poly multiplier, const poly monom, const poly syzterm, const CReducerFinder& checker) const;
272
273#endif
274    // TODO: save shortcut (syz: |-.->) LM(LM(m) * "t") -> syz?
275    poly // const_iterator // TODO: return const_iterator it, s.th: it->m_lt is the needed
276        FindReducer(const poly product, const poly syzterm, const CReducerFinder& checker) const;
277
278    bool IsDivisible(const poly q) const;
279
280
281    inline bool IsNonempty() const { return !m_hash.empty(); }
282
283    /// is the term to be "preprocessed" as lower order term or lead to only reducible syzygies...
284    int PreProcessTerm(const poly t, CReducerFinder& syzChecker) const;
285
286  private:
287    ideal m_L; ///< only for debug
288
289    CReducersHash m_hash; // can also be replaced with a vector indexed by components
290
291  private:
292    CReducerFinder(const CReducerFinder&);
293    void operator=(const CReducerFinder&);
294};
295
296bool my_p_LmCmp (poly, poly, const ring);
297
298typedef poly TCacheKey;
299typedef poly TCacheValue;
300
301struct CCacheCompare
302{
303  const ring & m_ring;
304
305  CCacheCompare();
306
307  CCacheCompare(const ring& r): m_ring(r) { assume(r != NULL); }
308
309  CCacheCompare(const CCacheCompare& lhs): m_ring(lhs.m_ring) { assume(m_ring != NULL); }
310  CCacheCompare& operator=(const CCacheCompare& lhs) { assume(lhs.m_ring != NULL); return (const_cast<CCacheCompare&>(lhs)); }
311
312  inline bool operator() (const TCacheKey& l, const TCacheKey& r) const { assume(m_ring != NULL); return my_p_LmCmp(l, r, m_ring); }
313};
314
315typedef std::map<TCacheKey, TCacheValue, CCacheCompare> TP2PCache; // deallocation??? !!!
316typedef std::map<int, TP2PCache> TCache;
317
318
319/** @class SchreyerSyzygyComputation syzextra.h
320 *
321 * Computing syzygies after Schreyer
322 *
323 * Storing/accumulating data during the computation requires some global
324 * object, like this class. Ideally the above global functions should not
325 * be used in favour of this class.
326 *
327 * @sa Schreyer Syzygy Computation Paper & Talk & Python prototype
328 */
329class SchreyerSyzygyComputation: public SchreyerSyzygyComputationFlags
330{
331  friend class CLCM;
332  friend class CReducerFinder;
333
334  public:
335    /// Construct a global object for given input data (separated into leads & tails)
336    SchreyerSyzygyComputation(const ideal idLeads, const ideal idTails, const SchreyerSyzygyComputationFlags setting):
337        SchreyerSyzygyComputationFlags(setting),
338        m_idLeads(idLeads), m_idTails(id_Copy(idTails, setting.m_rBaseRing)),
339        m_syzLeads(NULL), m_syzTails(NULL),
340        m_LS(NULL), m_lcm(m_idLeads, setting),
341        m_div(m_idLeads, setting), m_checker(NULL, setting), m_cache(),
342        m_sum_bucket_factory(setting.m_rBaseRing),
343        m_spoly_bucket(NULL)
344    {
345      if( UNLIKELY(OPT__PROT) ) memset( &m_stat, 0, sizeof(m_stat) );
346    }
347
348    /// Construct a global object for given input data (separated into leads & tails)
349    SchreyerSyzygyComputation(const ideal idLeads, const ideal idTails, const ideal syzLeads, const SchreyerSyzygyComputationFlags setting):
350        SchreyerSyzygyComputationFlags(setting),
351        m_idLeads(idLeads), m_idTails(id_Copy(idTails, setting.m_rBaseRing)),
352        m_syzLeads(syzLeads), m_syzTails(NULL),
353        m_LS(syzLeads), m_lcm(m_idLeads, setting),
354        m_div(m_idLeads, setting), m_checker(NULL, setting), m_cache(),
355        m_sum_bucket_factory(setting.m_rBaseRing),
356        m_spoly_bucket(NULL)
357    {
358      if( UNLIKELY(OPT__PROT) ) memset( &m_stat, 0, sizeof(m_stat) );
359
360      if( LIKELY(OPT__TAILREDSYZ && !OPT__IGNORETAILS) )
361      {
362        if (syzLeads != NULL)
363          m_checker.Initialize(syzLeads);
364//        if( idTails != NULL )
365//          SetUpTailTerms();
366      }
367    }
368
369    /// Destructor should not destruct the resulting m_syzLeads, m_syzTails.
370    ~SchreyerSyzygyComputation(){ CleanUp(); }
371
372    /// Convert the given ideal of tails into the internal representation (with reducers!)
373    /// Preprocess m_idTails as well...?
374    void SetUpTailTerms();
375
376    /// print statistics about the used heuristics
377    void PrintStats() const;
378
379    /// Read off the results while detaching them from this object
380    /// NOTE: no copy!
381    inline void ReadOffResult(ideal& syzL, ideal& syzT)
382    {
383      syzL = m_syzLeads; syzT = m_syzTails;
384
385      m_syzLeads = m_syzTails = NULL; // m_LS ?
386
387      if ( UNLIKELY(OPT__PROT) )
388        PrintStats();
389    }
390
391
392    /// The main driver function: computes
393    void ComputeSyzygy();
394
395    /// Computes Syz(leads) or only LEAD of it.
396    /// The result is stored into m_syzLeads
397    void ComputeLeadingSyzygyTerms(bool bComputeSecondTerms = true);
398
399
400
401    /// Main HybridNF == 1: poly reduce + LOT + LCM?
402    poly SchreyerSyzygyNF(const poly syz_lead, poly syz_2 = NULL) const;
403
404
405    // Main (HybridNF == 0) Tree Travers + LOT + LCM?
406    poly TraverseNF(const poly syz_lead, const poly syz_2 = NULL) const;
407
408    /// High level caching function!!!
409    poly TraverseTail(poly multiplier, const int tail) const;
410
411    // REMOVE?
412    /// called only from above and from outside (for testing)
413    poly TraverseTail(poly multiplier, poly tail) const;
414
415    /// TODO: save shortcut (syz: |-.->) LM(m) * "t" -> ? ???
416    poly ReduceTerm(poly multiplier, poly term4reduction, poly syztermCheck) const;
417
418    /// low level computation...
419    poly ComputeImage(poly multiplier, const int tail) const;
420
421  public:
422    /// just for testing via the wrapper below
423    inline poly _FindReducer(const poly product, const poly syzterm) const
424        { return m_div.FindReducer(product, syzterm, m_checker); }
425 private:
426    void CleanUp();
427  protected:
428
429
430    /// just leading terms
431    ideal Compute1LeadingSyzygyTerms();
432
433    /// leading + second terms
434    ideal Compute2LeadingSyzygyTerms();
435
436
437
438  private:
439    /// input leading terms
440    const ideal m_idLeads;
441
442    /// input tails
443    const ideal m_idTails;
444
445    /// output (syzygy) leading terms (+2nd terms?)
446    ideal m_syzLeads;
447
448    /// output (syzygy) tails
449    ideal m_syzTails;
450
451    /*mutable?*/ ideal m_LS; ///< leading syzygy terms used for reducing syzygy tails
452
453
454    /// Bitmask for variables occuring in leading terms
455    const CLCM m_lcm;
456
457    /// Divisor finder
458    const CReducerFinder m_div;
459
460    /// for checking tail-terms and makeing them irreducible (wrt m_LS!)
461    CReducerFinder m_checker;
462
463    mutable TCache m_cache; // cacher comp + poly -> poly! // mutable???
464
465    /// used for simple summing up
466    mutable SBucketFactory m_sum_bucket_factory; // sBucket_pt
467
468    /// for S-Polynomial reductions
469    mutable kBucket_pt m_spoly_bucket; // only used inside of SchreyerSyzygyNF! destruction by CleanUp()!
470
471
472    /// Statistics:
473    ///  0..3: as in SetUpTailTerms()::PreProcessTerm() // TODO!!??
474    ///  4: number of terms discarded due to LOT heuristics
475    ///  5: number of terms discarded due to LCM heuristics
476    ///  6, 7: lookups without & with rescale, 8: stores
477    mutable unsigned long m_stat[9];
478};
479
480// The following wrappers are just for testing separate functions on highest level (within schreyer.lib)
481
482static inline void ComputeSyzygy(const ideal L, const ideal T, ideal& LL, ideal& TT, const SchreyerSyzygyComputationFlags A)
483{
484  SchreyerSyzygyComputation syz(L, T, A);
485  syz.ComputeSyzygy();
486  syz.ReadOffResult(LL, TT);
487}
488
489static inline ideal ComputeLeadingSyzygyTerms(const ideal& L, const SchreyerSyzygyComputationFlags A)
490{
491  SchreyerSyzygyComputation syz(L, NULL, A);
492  syz.ComputeLeadingSyzygyTerms(false);
493  ideal LL, TT;
494  syz.ReadOffResult(LL, TT);
495  return LL; // assume TT is NULL!
496}
497
498static inline ideal Compute2LeadingSyzygyTerms(const ideal& L, const SchreyerSyzygyComputationFlags A)
499{
500  SchreyerSyzygyComputation syz(L, NULL, A);
501  syz.ComputeLeadingSyzygyTerms(true);
502  ideal LL, TT;
503  syz.ReadOffResult(LL, TT);
504  return LL; // assume TT is NULL!
505}
506
507static inline poly FindReducer(poly product, poly syzterm,
508                               ideal L, ideal LS, const SchreyerSyzygyComputationFlags A)
509{
510  SchreyerSyzygyComputation syz(L, NULL, LS, A);
511  return syz._FindReducer(product, syzterm);
512}
513
514static inline poly TraverseTail(poly multiplier, poly tail,
515                                ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
516{
517  SchreyerSyzygyComputation syz(L, T, LS, A);
518  return syz.TraverseTail(multiplier, tail);
519}
520
521static inline poly ReduceTerm(poly multiplier, poly term4reduction, poly syztermCheck,
522                              ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
523{
524  SchreyerSyzygyComputation syz(L, T, LS, A);
525  return syz.ReduceTerm(multiplier, term4reduction, syztermCheck);
526}
527
528
529static inline poly SchreyerSyzygyNF(poly syz_lead, poly syz_2,
530                                    ideal L, ideal T, ideal LS, const SchreyerSyzygyComputationFlags A)
531{
532  SchreyerSyzygyComputation syz(L, T, LS, A);
533  return syz.SchreyerSyzygyNF(syz_lead, syz_2);
534}
535
536#endif
537/* #ifndef SYZEXTRA_H */
538
539// Vi-modeline: vim: filetype=c:syntax:shiftwidth=2:tabstop=8:textwidth=0:expandtab
540
Note: See TracBrowser for help on using the repository browser.