source: git/dyn_modules/syzextra/syzextra.cc @ 1cf13b

jengelh-datetimespielwiese
Last change on this file since 1cf13b was 1cf13b, checked in by Oleksandr Motsak <motsak@…>, 9 years ago
Traverse API redesign + avoid multiplication as far as possible add/chg: TraverseNF similar to SchreyerSyzygyNF add/chg: use TraverseTail(mult, int tail_index) everywhere add: usage of CReducerFinder::FindReducer controlled by NOPRODUCT macro define add: _p_LmDivisibleByNoComp, CReducerFinder::FindReducer for products NOTE: needs p_GetShortExpVector for 'products'
  • Property mode set to 100644
File size: 30.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.cc
6 *
7 * Here we implement the Computation of Syzygies
8 *
9 * ABSTRACT: Computation of Syzygies due to Schreyer
10 *
11 * @author Oleksandr Motsak
12 *
13 **/
14/*****************************************************************************/
15
16// include header file
17#include <kernel/mod2.h>
18
19#include "syzextra.h"
20
21#include "DebugPrint.h"
22
23#include <omalloc/omalloc.h>
24
25#include <misc/intvec.h>
26#include <misc/options.h>
27
28#include <coeffs/coeffs.h>
29
30#include <polys/monomials/p_polys.h>
31#include <polys/monomials/ring.h>
32
33#include <kernel/kstd1.h>
34#include <kernel/polys.h>
35#include <kernel/syz.h>
36#include <kernel/ideals.h>
37
38
39
40#include <Singular/tok.h>
41#include <Singular/ipid.h>
42#include <Singular/lists.h>
43#include <Singular/attrib.h>
44
45#include <Singular/ipid.h> 
46#include <Singular/ipshell.h> // For iiAddCproc
47
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51
52// USING_NAMESPACE_SINGULARXX;
53USING_NAMESPACE( SINGULARXXNAME :: DEBUG )
54
55
56BEGIN_NAMESPACE_SINGULARXX     BEGIN_NAMESPACE(SYZEXTRA)
57
58
59BEGIN_NAMESPACE(SORT_c_ds)
60
61
62#ifdef _GNU_SOURCE
63static int cmp_c_ds(const void *p1, const void *p2, void *R)
64{
65#else
66static int cmp_c_ds(const void *p1, const void *p2)
67{
68  void *R = currRing; 
69#endif
70
71  const int YES = 1;
72  const int NO = -1;
73
74  const ring r =  (const ring) R; // TODO/NOTE: the structure is known: C, lp!!!
75
76  assume( r == currRing );
77
78  const poly a = *(const poly*)p1;
79  const poly b = *(const poly*)p2;
80
81  assume( a != NULL );
82  assume( b != NULL );
83
84  assume( p_LmTest(a, r) );
85  assume( p_LmTest(b, r) );
86
87
88  const signed long iCompDiff = p_GetComp(a, r) - p_GetComp(b, r);
89
90  // TODO: test this!!!!!!!!!!!!!!!!
91
92  //return -( compare (c, qsorts) )
93
94#ifndef NDEBUG
95  const int __DEBUG__ = 0;
96  if( __DEBUG__ )
97  {
98    PrintS("cmp_c_ds: a, b: \np1: "); dPrint(a, r, r, 2);
99    PrintS("b: "); dPrint(b, r, r, 2);
100    PrintLn();
101  }
102#endif
103
104
105  if( iCompDiff > 0 )
106    return YES;
107
108  if( iCompDiff < 0 )
109    return  NO;
110
111  assume( iCompDiff == 0 );
112
113  const signed long iDegDiff = p_Totaldegree(a, r) - p_Totaldegree(b, r);
114
115  if( iDegDiff > 0 )
116    return YES;
117
118  if( iDegDiff < 0 )
119    return  NO;
120
121  assume( iDegDiff == 0 );
122
123#ifndef NDEBUG
124  if( __DEBUG__ )
125  {
126    PrintS("cmp_c_ds: a & b have the same comp & deg! "); PrintLn();
127  }
128#endif
129
130  for (int v = rVar(r); v > 0; v--)
131  {
132    assume( v > 0 );
133    assume( v <= rVar(r) );
134
135    const signed int d = p_GetExp(a, v, r) - p_GetExp(b, v, r);
136
137    if( d > 0 )
138      return YES;
139
140    if( d < 0 )
141      return NO;
142
143    assume( d == 0 );
144  }
145
146  return 0; 
147}
148
149END_NAMESPACE
150/* namespace SORT_c_ds */
151
152/// return a new term: leading coeff * leading monomial of p
153/// with 0 leading component!
154poly leadmonom(const poly p, const ring r)
155{
156  poly m = NULL;
157
158  if( p != NULL )
159  {
160    assume( p != NULL );
161    assume( p_LmTest(p, r) );
162
163    m = p_LmInit(p, r);
164    p_SetCoeff0(m, n_Copy(p_GetCoeff(p, r), r), r);
165
166    p_SetComp(m, 0, r);
167    p_Setm(m, r);
168
169    assume( p_GetComp(m, r) == 0 );
170    assume( m != NULL );
171    assume( pNext(m) == NULL );
172    assume( p_LmTest(m, r) );
173  }
174
175  return m;
176}
177
178
179   
180poly p_Tail(const poly p, const ring r)
181{
182  if( p == NULL)
183    return NULL;
184  else
185    return p_Copy( pNext(p), r );
186}
187
188
189ideal id_Tail(const ideal id, const ring r)
190{
191  if( id == NULL)
192    return NULL;
193
194  const ideal newid = idInit(IDELEMS(id),id->rank);
195 
196  for (int i=IDELEMS(id) - 1; i >= 0; i--)
197    newid->m[i] = p_Tail( id->m[i], r );
198
199  newid->rank = id_RankFreeModule(newid, currRing);
200
201  return newid; 
202}
203
204
205
206void Sort_c_ds(const ideal id, const ring r)
207{
208  const int sizeNew = IDELEMS(id);
209
210#ifdef _GNU_SOURCE
211#define qsort_my(m, s, ss, r, cmp) qsort_r(m, s, ss, cmp, r)
212#else
213#define qsort_my(m, s, ss, r, cmp) qsort_r(m, s, ss, cmp)
214#endif
215 
216  if( sizeNew >= 2 )
217    qsort_my(id->m, sizeNew, sizeof(poly), r, FROM_NAMESPACE(SORT_c_ds, cmp_c_ds));
218
219#undef qsort_my
220
221  id->rank = id_RankFreeModule(id, r);
222}
223
224ideal SchreyerSyzygyComputation::Compute1LeadingSyzygyTerms()
225{
226  const ideal& id = m_idLeads;
227  const ring& r = m_rBaseRing;
228//  const SchreyerSyzygyComputationFlags& attributes = m_atttributes;
229
230//   const BOOLEAN __DEBUG__      = attributes.__DEBUG__;
231//   const BOOLEAN __SYZCHECK__   = attributes.__SYZCHECK__;
232//   const BOOLEAN __LEAD2SYZ__   = attributes.__LEAD2SYZ__;
233//   const BOOLEAN __HYBRIDNF__   = attributes.__HYBRIDNF__;
234//   const BOOLEAN __TAILREDSYZ__ = attributes.__TAILREDSYZ__;
235
236  assume(!__LEAD2SYZ__);
237
238  // 1. set of components S?
239  // 2. for each component c from S: set of indices of leading terms
240  // with this component?
241  // 3. short exp. vectors for each leading term?
242
243  const int size = IDELEMS(id);
244
245  if( size < 2 )
246  {
247    const ideal newid = idInit(1, 0); newid->m[0] = NULL; // zero ideal...       
248    return newid;
249  }
250
251  // TODO/NOTE: input is supposed to be (reverse-) sorted wrt "(c,ds)"!??
252
253  // components should come in groups: count elements in each group
254  // && estimate the real size!!!
255
256
257  // use just a vector instead???
258  const ideal newid = idInit( (size * (size-1))/2, size); // maximal size: ideal case!
259
260  int k = 0;
261
262  for (int j = 0; j < size; j++)
263  {
264    const poly p = id->m[j];
265    assume( p != NULL );
266    const int  c = p_GetComp(p, r);
267
268    for (int i = j - 1; i >= 0; i--)
269    {
270      const poly pp = id->m[i];
271      assume( pp != NULL );
272      const int  cc = p_GetComp(pp, r);
273
274      if( c != cc )
275        continue;
276
277      const poly m = p_Init(r); // p_New???
278
279      // m = LCM(p, pp) / p! // TODO: optimize: knowing the ring structure: (C/lp)!
280      for (int v = rVar(r); v > 0; v--)
281      {
282        assume( v > 0 );
283        assume( v <= rVar(r) );
284
285        const short e1 = p_GetExp(p , v, r);
286        const short e2 = p_GetExp(pp, v, r);
287
288        if( e1 >= e2 )
289          p_SetExp(m, v, 0, r);
290        else
291          p_SetExp(m, v, e2 - e1, r);
292
293      }
294
295      assume( (j > i) && (i >= 0) );
296
297      p_SetComp(m, j + 1, r);
298      pNext(m) = NULL;
299      p_SetCoeff0(m, n_Init(1, r->cf), r); // for later...
300
301      p_Setm(m, r); // should not do anything!!!
302
303      newid->m[k++] = m;
304    }
305  }
306
307//   if( __DEBUG__ && FALSE )
308//   {
309//     PrintS("ComputeLeadingSyzygyTerms::Temp0: \n");
310//     dPrint(newid, r, r, 1);
311//   }
312
313  // the rest of newid is assumed to be zeroes...
314
315  // simplify(newid, 2 + 32)??
316  // sort(newid, "C,ds")[1]???
317  id_DelDiv(newid, r); // #define SIMPL_LMDIV 32
318
319//   if( __DEBUG__ && FALSE )
320//   {
321//     PrintS("ComputeLeadingSyzygyTerms::Temp1: \n");
322//     dPrint(newid, r, r, 1);
323//   }
324
325  idSkipZeroes(newid); // #define SIMPL_NULL 2
326
327//   if( __DEBUG__ )
328//   {
329//     PrintS("ComputeLeadingSyzygyTerms::Output: \n");
330//     dPrint(newid, r, r, 1);
331//   }
332
333  Sort_c_ds(newid, r);
334
335  return newid;
336}
337
338ideal SchreyerSyzygyComputation::Compute2LeadingSyzygyTerms()
339{
340  const ideal& id = m_idLeads;
341  const ring& r = m_rBaseRing;
342//  const SchreyerSyzygyComputationFlags& attributes = m_atttributes;
343 
344//   const BOOLEAN __DEBUG__      = attributes.__DEBUG__;
345//   const BOOLEAN __SYZCHECK__   = attributes.__SYZCHECK__;
346//   const BOOLEAN __LEAD2SYZ__   = attributes.__LEAD2SYZ__;
347//   const BOOLEAN __HYBRIDNF__   = attributes.__HYBRIDNF__;
348//  const BOOLEAN __TAILREDSYZ__ = attributes.__TAILREDSYZ__;
349 
350
351  // 1. set of components S?
352  // 2. for each component c from S: set of indices of leading terms
353  // with this component?
354  // 3. short exp. vectors for each leading term?
355
356  const int size = IDELEMS(id);
357
358  if( size < 2 )
359  {
360    const ideal newid = idInit(1, 1); newid->m[0] = NULL; // zero module...   
361    return newid;
362  }
363
364
365  // TODO/NOTE: input is supposed to be sorted wrt "C,ds"!??
366 
367  // components should come in groups: count elements in each group
368  // && estimate the real size!!!
369
370
371  // use just a vector instead???
372  ideal newid = idInit( (size * (size-1))/2, size); // maximal size: ideal case!
373
374  int k = 0;
375
376  for (int j = 0; j < size; j++)
377  {
378    const poly p = id->m[j];
379    assume( p != NULL );
380    const int  c = p_GetComp(p, r);
381
382    for (int i = j - 1; i >= 0; i--)
383    {
384      const poly pp = id->m[i];
385      assume( pp != NULL );
386      const int  cc = p_GetComp(pp, r);
387
388      if( c != cc )
389        continue;
390
391        // allocate memory & zero it out!
392      const poly m = p_Init(r); const poly mm = p_Init(r);
393
394
395        // m = LCM(p, pp) / p! mm = LCM(p, pp) / pp!
396        // TODO: optimize: knowing the ring structure: (C/lp)!
397
398      for (int v = rVar(r); v > 0; v--)
399      {
400        assume( v > 0 );
401        assume( v <= rVar(r) );
402
403        const short e1 = p_GetExp(p , v, r);
404        const short e2 = p_GetExp(pp, v, r);
405
406        if( e1 >= e2 )
407          p_SetExp(mm, v, e1 - e2, r); //            p_SetExp(m, v, 0, r);
408        else
409          p_SetExp(m, v, e2 - e1, r); //            p_SetExp(mm, v, 0, r);
410
411      }
412
413      assume( (j > i) && (i >= 0) );
414
415      p_SetComp(m, j + 1, r);
416      p_SetComp(mm, i + 1, r);
417
418      const number& lc1 = p_GetCoeff(p , r);
419      const number& lc2 = p_GetCoeff(pp, r);
420
421      number g = n_Lcm( lc1, lc2, r );
422
423      p_SetCoeff0(m ,       n_Div(g, lc1, r), r);
424      p_SetCoeff0(mm, n_Neg(n_Div(g, lc2, r), r), r);
425
426      n_Delete(&g, r);
427
428      p_Setm(m, r); // should not do anything!!!
429      p_Setm(mm, r); // should not do anything!!!
430
431      pNext(m) = mm; //        pNext(mm) = NULL;
432
433      newid->m[k++] = m;
434    }
435  }
436
437//   if( __DEBUG__ && FALSE )
438//   {
439//     PrintS("Compute2LeadingSyzygyTerms::Temp0: \n");
440//     dPrint(newid, r, r, 1);
441//   }
442
443  if( !__TAILREDSYZ__ )
444  {
445      // simplify(newid, 2 + 32)??
446      // sort(newid, "C,ds")[1]???
447    id_DelDiv(newid, r); // #define SIMPL_LMDIV 32
448
449//     if( __DEBUG__ && FALSE )
450//     {
451//       PrintS("Compute2LeadingSyzygyTerms::Temp1 (deldiv): \n");
452//       dPrint(newid, r, r, 1);
453//     }
454  }
455  else
456  {
457      //      option(redSB); option(redTail);
458      //      TEST_OPT_REDSB
459      //      TEST_OPT_REDTAIL
460    assume( r == currRing );
461    BITSET _save_test = test;
462    test |= (Sy_bit(OPT_REDTAIL) | Sy_bit(OPT_REDSB));
463
464    intvec* w=new intvec(IDELEMS(newid));
465    ideal tmp = kStd(newid, currQuotient, isHomog, &w);
466    delete w;
467
468    test = _save_test;
469
470    id_Delete(&newid, r);
471    newid = tmp;
472
473//     if( __DEBUG__ && FALSE )
474//     {
475//       PrintS("Compute2LeadingSyzygyTerms::Temp1 (std): \n");
476//       dPrint(newid, r, r, 1);
477//     }
478
479  }
480
481  idSkipZeroes(newid);
482
483  Sort_c_ds(newid, r);
484 
485  return newid;
486}
487
488poly SchreyerSyzygyComputation::TraverseNF(const poly a, const poly a2) const
489{
490  const ideal& L = m_idLeads;
491  const ideal& T = m_idTails;
492
493  const ring& R = m_rBaseRing;
494
495  const int r = p_GetComp(a, R) - 1; 
496
497  assume( r >= 0 && r < IDELEMS(T) );
498  assume( r >= 0 && r < IDELEMS(L) );
499
500  poly aa = leadmonom(a, R); assume( aa != NULL); // :(
501  poly t = TraverseTail(aa, r);
502
503  if( a2 != NULL )
504  {
505    assume( __LEAD2SYZ__ );
506
507    const int r2 = p_GetComp(a2, R) - 1; poly aa2 = leadmonom(a2, R); // :(
508
509    assume( r2 >= 0 && r2 < IDELEMS(T) );
510
511    t = p_Add_q(a2, p_Add_q(t, TraverseTail(aa2, r2), R), R);
512
513    p_Delete(&aa2, R);
514  } else
515    t = p_Add_q(t, ReduceTerm(aa, L->m[r], a), R);
516
517  p_Delete(&aa, R);
518
519  return t;
520}
521
522
523
524void SchreyerSyzygyComputation::ComputeSyzygy()
525{
526  assume( m_idLeads != NULL );
527  assume( m_idTails != NULL );
528 
529  const ideal& L = m_idLeads;
530  const ideal& T = m_idTails;
531
532  ideal& TT = m_syzTails;
533  const ring& R = m_rBaseRing;
534
535  assume( IDELEMS(L) == IDELEMS(T) );
536
537  if( m_syzLeads == NULL )
538    ComputeLeadingSyzygyTerms( __LEAD2SYZ__ && !__IGNORETAILS__ ); // 2 terms OR 1 term!
539
540  assume( m_syzLeads != NULL );
541
542  ideal& LL = m_syzLeads;
543
544 
545  const int size = IDELEMS(LL);
546
547  TT = idInit(size, 0);
548
549  if( size == 1 && LL->m[0] == NULL )
550    return;
551
552
553  for( int k = size - 1; k >= 0; k-- )
554  {
555    const poly a = LL->m[k]; assume( a != NULL );
556
557    poly a2 = pNext(a);   
558
559    // Splitting 2-terms Leading syzygy module
560    if( a2 != NULL )
561      pNext(a) = NULL;
562
563    if( __IGNORETAILS__ )
564    {
565      TT->m[k] = NULL;
566
567      assume( a2 != NULL );
568
569      if( a2 != NULL )
570        p_Delete(&a2, R);
571
572      continue;
573    }
574   
575//    TT->m[k] = a2;
576
577    if( ! __HYBRIDNF__ )
578    {
579      TT->m[k] = TraverseNF(a, a2);
580    } else
581    {
582      TT->m[k] = SchreyerSyzygyNF(a, a2);
583    }
584
585  }
586
587  TT->rank = id_RankFreeModule(TT, R);
588}
589
590void SchreyerSyzygyComputation::ComputeLeadingSyzygyTerms(bool bComputeSecondTerms)
591{
592//  const SchreyerSyzygyComputationFlags& attributes = m_atttributes;
593
594//  const BOOLEAN __LEAD2SYZ__   = attributes.__LEAD2SYZ__;
595//  const BOOLEAN __TAILREDSYZ__ = attributes.__TAILREDSYZ__;
596
597  assume( m_syzLeads == NULL );
598
599  if( bComputeSecondTerms )
600  {
601    assume( __LEAD2SYZ__ );
602//    m_syzLeads = FROM_NAMESPACE(INTERNAL, _Compute2LeadingSyzygyTerms(m_idLeads, m_rBaseRing, m_atttributes));
603    m_syzLeads = Compute2LeadingSyzygyTerms();
604  }
605  else
606  {
607    assume( !__LEAD2SYZ__ );
608   
609    m_syzLeads = Compute1LeadingSyzygyTerms();
610  }
611//    m_syzLeads = FROM_NAMESPACE(INTERNAL, _ComputeLeadingSyzygyTerms(m_idLeads, m_rBaseRing, m_atttributes));
612 
613  // NOTE: set m_LS if tails are to be reduced!
614  assume( m_syzLeads!= NULL );
615
616  if (__TAILREDSYZ__ && !__IGNORETAILS__ && (IDELEMS(m_syzLeads) > 0) && !((IDELEMS(m_syzLeads) == 1) && (m_syzLeads->m[0] == NULL)))
617  {
618    m_LS = m_syzLeads;
619    m_checker.Initialize(m_syzLeads);
620#ifndef NDEBUG   
621    if( __DEBUG__ )
622    {
623      const ring& r = m_rBaseRing;
624      PrintS("SchreyerSyzygyComputation::ComputeLeadingSyzygyTerms: \n");
625      PrintS("m_syzLeads: \n");
626      dPrint(m_syzLeads, r, r, 1);
627      PrintS("m_checker.Initialize(m_syzLeads) => \n");
628      m_checker.DebugPrint();
629    }
630#endif
631    assume( m_checker.IsNonempty() ); // TODO: this always fails... BUG????
632  }
633}
634
635#define NOPRODUCT 1
636
637poly SchreyerSyzygyComputation::SchreyerSyzygyNF(const poly syz_lead, poly syz_2) const
638{
639 
640  assume( !__IGNORETAILS__ );
641
642  const ideal& L = m_idLeads;
643  const ideal& T = m_idTails;
644  const ring& r = m_rBaseRing;
645
646  assume( syz_lead != NULL );
647
648  if( syz_2 == NULL )
649  {
650    const int rr = p_GetComp(syz_lead, r) - 1; 
651
652    assume( rr >= 0 && rr < IDELEMS(T) );
653    assume( rr >= 0 && rr < IDELEMS(L) );
654
655
656#if NOPRODUCT
657    syz_2 = m_div.FindReducer(syz_lead, L->m[rr], syz_lead, m_checker);
658#else   
659    poly aa = leadmonom(syz_lead, r); assume( aa != NULL); // :(
660    aa = p_Mult_mm(aa, L->m[rr], r);
661
662    syz_2 = m_div.FindReducer(aa, syz_lead, m_checker);
663
664    p_Delete(&aa, r);
665#endif
666   
667    assume( syz_2 != NULL ); // by construction of S-Polynomial   
668  }
669
670
671 
672  assume( syz_2 != NULL );
673
674  assume( L != NULL );
675  assume( T != NULL );
676
677  assume( IDELEMS(L) == IDELEMS(T) );
678
679  int  c = p_GetComp(syz_lead, r) - 1;
680
681  assume( c >= 0 && c < IDELEMS(T) );
682
683  poly p = leadmonom(syz_lead, r); // :( 
684  poly spoly = pp_Mult_qq(p, T->m[c], r);
685  p_Delete(&p, r);
686
687
688  c = p_GetComp(syz_2, r) - 1;
689  assume( c >= 0 && c < IDELEMS(T) );
690
691  p = leadmonom(syz_2, r); // :(
692  spoly = p_Add_q(spoly, pp_Mult_qq(p, T->m[c], r), r);
693  p_Delete(&p, r);
694
695  poly tail = syz_2; // TODO: use bucket!?
696
697  while (spoly != NULL)
698  {
699    poly t = m_div.FindReducer(spoly, NULL, m_checker);
700
701    p_LmDelete(&spoly, r);
702
703    if( t != NULL )
704    {
705      p = leadmonom(t, r); // :(
706      c = p_GetComp(t, r) - 1;
707
708      assume( c >= 0 && c < IDELEMS(T) );
709
710      spoly = p_Add_q(spoly, pp_Mult_qq(p, T->m[c], r), r);
711
712      p_Delete(&p, r);
713
714      tail = p_Add_q(tail, t, r);
715    }   
716  }
717
718  return tail;
719}
720
721poly SchreyerSyzygyComputation::TraverseTail(poly multiplier, const int tail) const
722{
723  // TODO: store (multiplier, tail) -.-^-.-^-.--> !
724  assume(m_idTails !=  NULL && m_idTails->m != NULL);
725  assume( tail >= 0 && tail < IDELEMS(m_idTails) );
726
727  const poly t = m_idTails->m[tail];
728
729  if(t != NULL)
730    return TraverseTail(multiplier, t);
731
732  return NULL;
733}
734
735
736poly SchreyerSyzygyComputation::TraverseTail(poly multiplier, poly tail) const
737{
738  assume( !__IGNORETAILS__ );
739
740  const ideal& L = m_idLeads;
741  const ideal& T = m_idTails;
742  const ring& r = m_rBaseRing;
743
744  assume( multiplier != NULL );
745
746  assume( L != NULL );
747  assume( T != NULL );
748
749  poly s = NULL;
750
751  if( (!__TAILREDSYZ__) || m_lcm.Check(multiplier) )
752    for(poly p = tail; p != NULL; p = pNext(p))   // iterate over the tail
753      s = p_Add_q(s, ReduceTerm(multiplier, p, NULL), r); 
754
755  return s;
756}
757
758
759
760
761poly SchreyerSyzygyComputation::ReduceTerm(poly multiplier, poly term4reduction, poly syztermCheck) const
762{
763  assume( !__IGNORETAILS__ );
764
765  const ideal& L = m_idLeads;
766  const ideal& T = m_idTails;
767  const ring& r = m_rBaseRing;
768
769  assume( multiplier != NULL );
770  assume( term4reduction != NULL );
771
772
773  assume( L != NULL );
774  assume( T != NULL );
775
776  // simple implementation with FindReducer:
777  poly s = NULL;
778
779  if( (!__TAILREDSYZ__) || m_lcm.Check(multiplier) )
780  {
781#if NOPRODUCT
782    s = m_div.FindReducer(multiplier, term4reduction, syztermCheck, m_checker);
783#else   
784    // NOTE: only LT(term4reduction) should be used in the following:
785    poly product = pp_Mult_mm(multiplier, term4reduction, r);
786    s = m_div.FindReducer(product, syztermCheck, m_checker);
787    p_Delete(&product, r);
788#endif
789  }
790
791  if( s == NULL ) // No Reducer?
792    return s;
793
794  poly b = leadmonom(s, r);
795
796  const int c = p_GetComp(s, r) - 1;
797  assume( c >= 0 && c < IDELEMS(T) );
798
799  const poly t = TraverseTail(b, c); // T->m[c];
800
801  if( t != NULL )
802    s = p_Add_q(s, t, r); 
803
804  return s;
805}
806
807
808
809
810
811BEGIN_NAMESPACE_NONAME
812   
813static inline int atGetInt(idhdl rootRingHdl, const char* attribute, long def)
814{
815  return ((int)(long)(atGet(rootRingHdl, attribute, INT_CMD, (void*)def)));
816}
817
818END_NAMESPACE   
819
820SchreyerSyzygyComputationFlags::SchreyerSyzygyComputationFlags(idhdl rootRingHdl):
821#ifndef NDEBUG
822    __DEBUG__( (BOOLEAN)atGetInt(rootRingHdl,"DEBUG", TRUE) ),
823#else
824    __DEBUG__( (BOOLEAN)atGetInt(rootRingHdl,"DEBUG", FALSE) ),
825#endif
826//    __SYZCHECK__( (BOOLEAN)atGetInt(rootRingHdl, "SYZCHECK", __DEBUG__) ),
827    __LEAD2SYZ__( (BOOLEAN)atGetInt(rootRingHdl, "LEAD2SYZ", 1) ), 
828    __TAILREDSYZ__( (BOOLEAN)atGetInt(rootRingHdl, "TAILREDSYZ", 1) ), 
829    __HYBRIDNF__( (BOOLEAN)atGetInt(rootRingHdl, "HYBRIDNF", 0) ),
830    __IGNORETAILS__( (BOOLEAN)atGetInt(rootRingHdl, "IGNORETAILS", 0) ),
831    m_rBaseRing( rootRingHdl->data.uring )
832{   
833  if( __DEBUG__ )
834  {
835    PrintS("SchreyerSyzygyComputationFlags: \n");
836    Print("        DEBUG: \t%d\n", __DEBUG__);
837//    Print("   SYZCHECK  : \t%d\n", __SYZCHECK__);
838    Print("     LEAD2SYZ: \t%d\n", __LEAD2SYZ__);
839    Print("   TAILREDSYZ: \t%d\n", __TAILREDSYZ__);
840    Print("  IGNORETAILS: \t%d\n", __IGNORETAILS__);
841   
842  }
843
844  // TODO: just current setting!
845  assume( rootRingHdl == currRingHdl );
846  assume( rootRingHdl->typ == RING_CMD );
847  assume( m_rBaseRing == currRing );
848  // move the global ring here inside???
849}
850
851   
852
853CReducerFinder::CLeadingTerm::CLeadingTerm(unsigned int _label,  const poly _lt, const ring R):
854    m_sev( p_GetShortExpVector(_lt, R) ),  m_label( _label ),  m_lt( _lt )
855{ }
856
857
858CReducerFinder::~CReducerFinder()
859{
860  for( CReducersHash::const_iterator it = m_hash.begin(); it != m_hash.end(); it++ )
861  {
862    const TReducers& v = it->second;
863    for(TReducers::const_iterator vit = v.begin(); vit != v.end(); vit++ )
864      delete const_cast<CLeadingTerm*>(*vit);
865  }
866}
867
868
869void CReducerFinder::Initialize(const ideal L)
870{
871  assume( m_L == NULL || m_L == L );
872  if( m_L == NULL )
873    m_L = L;
874
875  assume( m_L == L );
876 
877  if( L != NULL )
878  {
879    const ring& R = m_rBaseRing;
880    assume( R != NULL );
881   
882    for( int k = IDELEMS(L) - 1; k >= 0; k-- )
883    {
884      const poly a = L->m[k]; // assume( a != NULL );
885
886      // NOTE: label is k \in 0 ... |L|-1!!!
887      if( a != NULL )
888        m_hash[p_GetComp(a, R)].push_back( new CLeadingTerm(k, a, R) );
889    }
890  }
891}
892
893CReducerFinder::CReducerFinder(const ideal L, const SchreyerSyzygyComputationFlags& flags):
894    SchreyerSyzygyComputationFlags(flags),
895    m_L(const_cast<ideal>(L)), // for debug anyway
896    m_hash()
897{
898  assume( flags.m_rBaseRing == m_rBaseRing );
899  if( L != NULL )
900    Initialize(L);
901}
902
903
904bool CReducerFinder::IsDivisible(const poly product) const
905{
906  const ring& r = m_rBaseRing;
907 
908  const long comp = p_GetComp(product, r);
909  const unsigned long not_sev = ~p_GetShortExpVector(product, r);
910
911  assume( comp >= 0 );
912
913  CReducersHash::const_iterator it = m_hash.find(comp); // same module component
914
915  if( it == m_hash.end() )
916    return false;
917
918  assume( m_L != NULL ); 
919
920  const TReducers& reducers = it->second;
921
922  for(TReducers::const_iterator vit = reducers.begin(); vit != reducers.end(); vit++ )
923  {
924    const poly p = (*vit)->m_lt;
925
926    assume( p_GetComp(p, r) == comp );
927
928    const int k = (*vit)->m_label;
929
930    assume( m_L->m[k] == p );
931
932    const unsigned long p_sev = (*vit)->m_sev;
933
934    assume( p_sev == p_GetShortExpVector(p, r) );     
935
936    if( !p_LmShortDivisibleByNoComp(p, p_sev, product, not_sev, r) )
937      continue;
938
939    if( __DEBUG__ )
940    {
941      Print("_FindReducer::Test LS: q is divisible by LS[%d] !:((, diviser is: ", k+1);
942      dPrint(p, r, r, 1);
943    }
944
945    return true;
946  }
947
948  return false;
949}
950
951
952#ifndef NDEBUG
953void CReducerFinder::DebugPrint() const
954{
955  const ring& r = m_rBaseRing;
956
957  for( CReducersHash::const_iterator it = m_hash.begin(); it != m_hash.end(); it++)
958  {
959    Print("Hash Key: %d, Values: \n", it->first);
960    const TReducers& reducers = it->second;
961
962    for(TReducers::const_iterator vit = reducers.begin(); vit != reducers.end(); vit++ )
963    {
964      const poly p = (*vit)->m_lt;
965
966      assume( p_GetComp(p, r) == it->first );
967
968      const int k = (*vit)->m_label;
969
970      assume( m_L->m[k] == p );
971
972      const unsigned long p_sev = (*vit)->m_sev;
973
974      assume( p_sev == p_GetShortExpVector(p, r) );
975
976      Print("L[%d]: ", k); dPrint(p, r, r, 0); Print("SEV: %dl\n", p_sev);     
977    }
978  }
979}
980#endif
981
982
983/// _p_LmDivisibleByNoComp for a | b*c
984static inline BOOLEAN _p_LmDivisibleByNoComp(const poly a, const poly b, const poly c, const ring r)
985{
986  int i=r->VarL_Size - 1;
987  unsigned long divmask = r->divmask;
988  unsigned long la, lb;
989
990  if (r->VarL_LowIndex >= 0)
991  {
992    i += r->VarL_LowIndex;
993    do
994    {
995      la = a->exp[i];
996      lb = b->exp[i] + c->exp[i];
997      if ((la > lb) ||
998          (((la & divmask) ^ (lb & divmask)) != ((lb - la) & divmask)))
999      {
1000        pDivAssume(p_DebugLmDivisibleByNoComp(a, b, r) == FALSE);
1001        return FALSE;
1002      }
1003      i--;
1004    }
1005    while (i>=r->VarL_LowIndex);
1006  }
1007  else
1008  {
1009    do
1010    {
1011      la = a->exp[r->VarL_Offset[i]];
1012      lb = b->exp[r->VarL_Offset[i]] + c->exp[r->VarL_Offset[i]];
1013      if ((la > lb) ||
1014          (((la & divmask) ^ (lb & divmask)) != ((lb - la) & divmask)))
1015      {
1016        pDivAssume(p_DebugLmDivisibleByNoComp(a, b, r) == FALSE);
1017        return FALSE;
1018      }
1019      i--;
1020    }
1021    while (i>=0);
1022  }
1023#ifdef HAVE_RINGS
1024  assume( !rField_is_Ring(r) ); // not implemented for rings...!
1025#endif
1026  return TRUE;
1027}
1028
1029
1030poly CReducerFinder::FindReducer(const poly multiplier, const poly t,
1031                                 const poly syzterm, const CReducerFinder& syz_checker) const
1032{
1033  // don't case about the module component of multiplier (as it may be
1034  // the syzygy term)
1035  // product = multiplier * t?
1036  const ring& r = m_rBaseRing;
1037
1038  assume( multiplier != NULL ); assume( t != NULL );
1039
1040  const ideal& L = m_L; assume( L != NULL ); // for debug/testing only!
1041
1042  long c = 0;
1043
1044  if (syzterm != NULL)
1045    c = p_GetComp(syzterm, r) - 1;
1046
1047  assume( c >= 0 && c < IDELEMS(L) );
1048
1049  if (__DEBUG__ && (syzterm != NULL))
1050  {
1051    const poly m = L->m[c];
1052
1053    assume( m != NULL ); assume( pNext(m) == NULL );
1054
1055    poly lm = p_Mult_mm(leadmonom(syzterm, r), m, r);
1056
1057    poly pr = p_Mult_q( p_LmInit(multiplier, r), p_LmInit(t, r), r);
1058   
1059    assume( p_EqualPolys(lm, pr, r) );
1060
1061    //  def @@c = leadcomp(syzterm); int @@r = int(@@c);
1062    //  def @@product = leadmonomial(syzterm) * L[@@r];
1063
1064    p_Delete(&lm, r);   
1065    p_Delete(&pr, r);   
1066  }
1067
1068  const long comp = p_GetComp(t, r);
1069 
1070  const unsigned long not_sev = ~p_GetShortExpVector(multiplier, t, r); // !
1071
1072  assume( comp >= 0 );
1073
1074//   for( int k = IDELEMS(L)-1; k>= 0; k-- )
1075//   {
1076//     const poly p = L->m[k];
1077//
1078//     if ( p_GetComp(p, r) != comp )
1079//       continue;
1080//
1081//     const unsigned long p_sev = p_GetShortExpVector(p, r); // to be stored in m_hash!!!
1082
1083   // looking for an appropriate diviser p = L[k]...
1084  CReducersHash::const_iterator it = m_hash.find(comp); // same module component
1085
1086  if( it == m_hash.end() )
1087    return NULL;
1088
1089  assume( m_L != NULL );
1090
1091  const TReducers& reducers = it->second;
1092
1093  const BOOLEAN to_check = (syz_checker.IsNonempty()); // __TAILREDSYZ__ &&
1094
1095  const poly q = p_New(r); pNext(q) = NULL;
1096
1097  if( __DEBUG__ )
1098    p_SetCoeff0(q, 0, r); // for printing q
1099
1100  for(TReducers::const_iterator vit = reducers.begin(); vit != reducers.end(); vit++ )
1101  {
1102    const poly p = (*vit)->m_lt;
1103
1104    assume( p_GetComp(p, r) == comp );
1105
1106    const int k = (*vit)->m_label;
1107
1108    assume( L->m[k] == p );
1109
1110    const unsigned long p_sev = (*vit)->m_sev;
1111
1112    assume( p_sev == p_GetShortExpVector(p, r) );     
1113
1114//    if( !p_LmShortDivisibleByNoComp(p, p_sev, product, not_sev, r) )
1115//      continue;     
1116
1117    if (p_sev & not_sev)
1118      continue;
1119
1120    if( !_p_LmDivisibleByNoComp(p, multiplier, t, r) )
1121      continue;     
1122
1123
1124    p_ExpVectorSum(q, multiplier, t, r); // q == product == multiplier * t       
1125    p_ExpVectorDiff(q, q, p, r); // (LM(product) / LM(L[k]))
1126   
1127    p_SetComp(q, k + 1, r);
1128    p_Setm(q, r);
1129
1130    // cannot allow something like: a*gen(i) - a*gen(i)
1131    if (syzterm != NULL && (k == c))
1132      if (p_ExpVectorEqual(syzterm, q, r))
1133      {
1134        if( __DEBUG__ )
1135        {
1136          Print("_FindReducer::Test SYZTERM: q == syzterm !:((, syzterm is: ");
1137          dPrint(syzterm, r, r, 1);
1138        }   
1139
1140        continue;
1141      }
1142
1143    // while the complement (the fraction) is not reducible by leading syzygies
1144    if( to_check && syz_checker.IsDivisible(q) ) 
1145    {
1146      if( __DEBUG__ )
1147      {
1148        PrintS("_FindReducer::Test LS: q is divisible by LS[?] !:((: ");
1149      }
1150
1151      continue;
1152    }
1153
1154    number n = n_Mult( p_GetCoeff(multiplier, r), p_GetCoeff(t, r), r);
1155    p_SetCoeff0(q, n_Neg( n_Div(n, p_GetCoeff(p, r), r), r), r);
1156    n_Delete(&n, r);
1157   
1158    return q;
1159  }
1160
1161  p_LmFree(q, r);
1162
1163  return NULL;
1164}
1165
1166
1167poly CReducerFinder::FindReducer(const poly product, const poly syzterm, const CReducerFinder& syz_checker) const
1168{
1169  const ring& r = m_rBaseRing;
1170
1171  assume( product != NULL );
1172
1173  const ideal& L = m_L; assume( L != NULL ); // for debug/testing only!
1174
1175  long c = 0;
1176
1177  if (syzterm != NULL)
1178    c = p_GetComp(syzterm, r) - 1;
1179
1180  assume( c >= 0 && c < IDELEMS(L) );
1181
1182  if (__DEBUG__ && (syzterm != NULL))
1183  {
1184    const poly m = L->m[c];
1185
1186    assume( m != NULL ); assume( pNext(m) == NULL );
1187
1188    poly lm = p_Mult_mm(leadmonom(syzterm, r), m, r);
1189    assume( p_EqualPolys(lm, product, r) );
1190
1191    //  def @@c = leadcomp(syzterm); int @@r = int(@@c);
1192    //  def @@product = leadmonomial(syzterm) * L[@@r];
1193
1194    p_Delete(&lm, r);   
1195  }
1196
1197  const long comp = p_GetComp(product, r);
1198  const unsigned long not_sev = ~p_GetShortExpVector(product, r);
1199
1200  assume( comp >= 0 );
1201
1202//   for( int k = IDELEMS(L)-1; k>= 0; k-- )
1203//   {
1204//     const poly p = L->m[k];
1205//
1206//     if ( p_GetComp(p, r) != comp )
1207//       continue;
1208//
1209//     const unsigned long p_sev = p_GetShortExpVector(p, r); // to be stored in m_hash!!!
1210 
1211   // looking for an appropriate diviser p = L[k]...
1212  CReducersHash::const_iterator it = m_hash.find(comp); // same module component
1213
1214  if( it == m_hash.end() )
1215    return NULL;
1216
1217  assume( m_L != NULL );
1218
1219  const TReducers& reducers = it->second;
1220
1221  const BOOLEAN to_check = (syz_checker.IsNonempty()); // __TAILREDSYZ__ &&
1222
1223  const poly q = p_New(r); pNext(q) = NULL;
1224
1225  if( __DEBUG__ )
1226    p_SetCoeff0(q, 0, r); // for printing q
1227 
1228  for(TReducers::const_iterator vit = reducers.begin(); vit != reducers.end(); vit++ )
1229  {
1230    const poly p = (*vit)->m_lt;
1231
1232    assume( p_GetComp(p, r) == comp );
1233
1234    const int k = (*vit)->m_label;
1235
1236    assume( L->m[k] == p );
1237
1238    const unsigned long p_sev = (*vit)->m_sev;
1239
1240    assume( p_sev == p_GetShortExpVector(p, r) );     
1241
1242    if( !p_LmShortDivisibleByNoComp(p, p_sev, product, not_sev, r) )
1243      continue;     
1244
1245//     // ... which divides the product, looking for the _1st_ appropriate one!
1246//     if( !p_LmDivisibleByNoComp(p, product, r) ) // included inside  p_LmShortDivisibleBy!
1247//       continue;
1248
1249    p_ExpVectorDiff(q, product, p, r); // (LM(product) / LM(L[k]))
1250    p_SetComp(q, k + 1, r);
1251    p_Setm(q, r);
1252
1253    // cannot allow something like: a*gen(i) - a*gen(i)
1254    if (syzterm != NULL && (k == c))
1255      if (p_ExpVectorEqual(syzterm, q, r))
1256      {
1257        if( __DEBUG__ )
1258        {
1259          Print("_FindReducer::Test SYZTERM: q == syzterm !:((, syzterm is: ");
1260          dPrint(syzterm, r, r, 1);
1261        }   
1262
1263        continue;
1264      }
1265
1266    // while the complement (the fraction) is not reducible by leading syzygies
1267    if( to_check && syz_checker.IsDivisible(q) ) 
1268    {
1269      if( __DEBUG__ )
1270      {
1271        PrintS("_FindReducer::Test LS: q is divisible by LS[?] !:((: ");
1272      }
1273     
1274      continue;
1275    }
1276
1277    p_SetCoeff0(q, n_Neg( n_Div( p_GetCoeff(product, r), p_GetCoeff(p, r), r), r), r);
1278    return q;
1279  }
1280
1281  p_LmFree(q, r);
1282
1283  return NULL;
1284}
1285
1286
1287
1288CLCM::CLCM(const ideal& L, const SchreyerSyzygyComputationFlags& flags):
1289    SchreyerSyzygyComputationFlags(flags), std::vector<bool>(),
1290    m_compute(false), m_N(rVar(flags.m_rBaseRing))
1291{
1292  const ring& R = m_rBaseRing;
1293  assume( flags.m_rBaseRing == R );
1294  assume( R != NULL );
1295
1296  assume( L != NULL );
1297
1298  if( __TAILREDSYZ__ && !__HYBRIDNF__ && (L != NULL))
1299  {
1300    const int l = IDELEMS(L);
1301
1302    assume( l > 0 );
1303
1304    resize(l, false);
1305
1306    for( int k = l - 1; k >= 0; k-- )
1307    {
1308      const poly a = L->m[k]; assume( a != NULL );
1309
1310      for (unsigned int j = m_N; j > 0; j--)
1311        if ( !(*this)[j] )
1312          (*this)[j] = (p_GetExp(a, j, R) > 0);
1313    }
1314
1315    m_compute = true;   
1316  }
1317}
1318
1319
1320bool CLCM::Check(const poly m) const
1321{
1322  assume( m != NULL );
1323  if( m_compute && (m != NULL))
1324  { 
1325    const ring& R = m_rBaseRing;
1326
1327    assume( __TAILREDSYZ__ && !__HYBRIDNF__ );
1328
1329    for (unsigned int j = m_N; j > 0; j--)
1330      if ( (*this)[j] )
1331        if(p_GetExp(m, j, R) > 0)
1332          return true;
1333
1334    return false;
1335
1336  } else return true;
1337}
1338
1339
1340
1341
1342END_NAMESPACE               END_NAMESPACE_SINGULARXX
1343
1344
1345// Vi-modeline: vim: filetype=c:syntax:shiftwidth=2:tabstop=8:textwidth=0:expandtab
Note: See TracBrowser for help on using the repository browser.