256 lines
6.9 KiB
C
256 lines
6.9 KiB
C
/*============================================================================
|
|
|
|
This file is part of FLINT.
|
|
|
|
FLINT is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
FLINT is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with FLINT; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===============================================================================*/
|
|
/******************************************************************************
|
|
|
|
linear_algebra.c
|
|
|
|
Routines for dealing with building the final F_2 matrix
|
|
|
|
(C) 2006, 2011 William Hart
|
|
|
|
******************************************************************************/
|
|
|
|
#define ulong ulongxx /* interferes with system includes */
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#undef ulong
|
|
#define ulong mp_limb_t
|
|
|
|
#include <gmp.h>
|
|
#include "flint.h"
|
|
#include "ulong_extras.h"
|
|
#include "qsieve.h"
|
|
#include "fmpz.h"
|
|
|
|
/*=========================================================================
|
|
|
|
Compare relations:
|
|
|
|
Function: Compare two relations; used by qsort
|
|
|
|
==========================================================================*/
|
|
|
|
int qsieve_ll_relations_cmp(const void * a, const void * b)
|
|
{
|
|
la_col_t * ra = *((la_col_t **) a);
|
|
la_col_t * rb = *((la_col_t **) b);
|
|
slong point;
|
|
|
|
if (ra->weight > rb->weight) return 1;
|
|
else if (ra->weight < rb->weight) return -1;
|
|
|
|
for (point = ra->weight - 1; point >= 0
|
|
&& (ra->data[point] == rb->data[point]); point--)
|
|
{
|
|
;
|
|
}
|
|
|
|
if (point == -1) return 0;
|
|
|
|
if (ra->data[point] > rb->data[point]) return 1;
|
|
else if (ra->data[point] < rb->data[point]) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int qsieve_ll_relations_cmp2(const void * a, const void * b)
|
|
{
|
|
la_col_t * ra = (la_col_t *) a;
|
|
la_col_t * rb = (la_col_t *) b;
|
|
slong point;
|
|
|
|
if (ra->weight > rb->weight) return 1;
|
|
else if (ra->weight < rb->weight) return -1;
|
|
|
|
for (point = ra->weight - 1; point >= 0
|
|
&& (ra->data[point] == rb->data[point]); point--)
|
|
{
|
|
;
|
|
}
|
|
|
|
if (point == -1) return 0;
|
|
|
|
if (ra->data[point] > rb->data[point]) return 1;
|
|
else if (ra->data[point] < rb->data[point]) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================================================
|
|
Merge sort:
|
|
|
|
Function: Merge a list of sorted new relations into a list of existing
|
|
sorted relations. Sort is done using a merge sort algorithm
|
|
with a short stack.
|
|
|
|
===========================================================================*/
|
|
|
|
slong qsieve_ll_merge_sort(qs_t qs_inf)
|
|
{
|
|
la_col_t * matrix = qs_inf->matrix;
|
|
slong columns = qs_inf->columns;
|
|
la_col_t ** qsort_arr = qs_inf->qsort_arr;
|
|
slong num_unmerged = qs_inf->num_unmerged;
|
|
slong dups = 0;
|
|
int comp;
|
|
slong i;
|
|
|
|
for (i = columns + num_unmerged - WORD(1); i >= dups; i--)
|
|
{
|
|
if (!columns) comp = -1;
|
|
else if (!num_unmerged) comp = 1;
|
|
else
|
|
comp = qsieve_ll_relations_cmp2(matrix + columns - WORD(1), qsort_arr[num_unmerged - WORD(1)]);
|
|
|
|
switch (comp)
|
|
{
|
|
case -1:
|
|
{
|
|
copy_col(matrix + i, qsort_arr[num_unmerged - WORD(1)]);
|
|
clear_col(qsort_arr[num_unmerged - WORD(1)]);
|
|
num_unmerged--;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
copy_col(matrix + i, matrix + columns - WORD(1));
|
|
columns--;
|
|
break;
|
|
}
|
|
case 0:
|
|
{
|
|
free_col(qsort_arr[num_unmerged - WORD(1)]);
|
|
clear_col(qsort_arr[num_unmerged - WORD(1)]);
|
|
num_unmerged--;
|
|
copy_col(matrix + i, matrix + columns - WORD(1));
|
|
columns--;
|
|
dups++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
columns = qs_inf->columns + qs_inf->num_unmerged - dups;
|
|
|
|
if (dups)
|
|
{
|
|
slong i;
|
|
for (i = 0; i < columns; i++)
|
|
copy_col(matrix + i, matrix + i + dups);
|
|
|
|
for ( ; i < columns + dups; i++)
|
|
clear_col(matrix + i);
|
|
}
|
|
|
|
qs_inf->columns = columns;
|
|
columns = qs_inf->num_unmerged - dups;
|
|
qs_inf->num_unmerged = 0;
|
|
|
|
#if (QS_DEBUG & 64)
|
|
flint_printf("%wd new, %wd dups\n", columns, dups);
|
|
#endif
|
|
|
|
return columns;
|
|
}
|
|
|
|
/*==========================================================================
|
|
Merge relations:
|
|
|
|
Function: Merge unmerged relations into the matrix
|
|
|
|
===========================================================================*/
|
|
|
|
slong qsieve_ll_merge_relations(qs_t qs_inf)
|
|
{
|
|
const slong num_unmerged = qs_inf->num_unmerged;
|
|
la_col_t * unmerged = qs_inf->unmerged;
|
|
la_col_t ** qsort_arr = qs_inf->qsort_arr;
|
|
|
|
if (num_unmerged)
|
|
{
|
|
slong i;
|
|
|
|
for (i = 0; i < num_unmerged; i++)
|
|
qsort_arr[i] = unmerged + i;
|
|
|
|
qsort(qsort_arr, num_unmerged, sizeof(la_col_t *), qsieve_ll_relations_cmp);
|
|
|
|
return qsieve_ll_merge_sort(qs_inf);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*==========================================================================
|
|
Insert relation:
|
|
|
|
Function: Insert the relation into the matrix and store the Y value
|
|
|
|
===========================================================================*/
|
|
|
|
slong qsieve_ll_insert_relation(qs_t qs_inf, fmpz_t Y)
|
|
{
|
|
la_col_t * unmerged = qs_inf->unmerged;
|
|
slong num_unmerged = qs_inf->num_unmerged;
|
|
slong * small = qs_inf->small;
|
|
slong num_factors = qs_inf->num_factors;
|
|
fac_t * factor = qs_inf->factor;
|
|
slong * curr_rel = qs_inf->curr_rel;
|
|
slong fac_num = 0;
|
|
slong i;
|
|
|
|
clear_col(unmerged + num_unmerged);
|
|
|
|
for (i = 0; i < qs_inf->small_primes; i++)
|
|
{
|
|
if (small[i] & 1) insert_col_entry(unmerged + num_unmerged, i);
|
|
if (small[i])
|
|
{
|
|
curr_rel[2*fac_num + 1] = i;
|
|
curr_rel[2*fac_num + 2] = small[i];
|
|
fac_num++;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < num_factors; i++)
|
|
{
|
|
if (factor[i].exp & 1) insert_col_entry(unmerged + num_unmerged, factor[i].ind);
|
|
curr_rel[2*fac_num + 1] = factor[i].ind;
|
|
curr_rel[2*fac_num + 2] = factor[i].exp;
|
|
fac_num++;
|
|
}
|
|
|
|
curr_rel[0] = fac_num;
|
|
|
|
unmerged[num_unmerged].orig = qs_inf->num_relations;
|
|
|
|
fmpz_set(qs_inf->Y_arr + qs_inf->num_relations, Y);
|
|
|
|
qs_inf->curr_rel += qs_inf->max_factors*2;
|
|
qs_inf->num_unmerged++;
|
|
qs_inf->num_relations++;
|
|
|
|
if (qs_inf->num_unmerged == qs_inf->qsort_rels)
|
|
return qsieve_ll_merge_relations(qs_inf);
|
|
|
|
return 0;
|
|
}
|
|
|