552 lines
12 KiB
C
552 lines
12 KiB
C
|
/*
|
||
|
Copyright 2015 Ian Jauslin
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#include "number.h"
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <math.h>
|
||
|
#include "istring.h"
|
||
|
#include "definitions.cpp"
|
||
|
#include "tools.h"
|
||
|
#include "rational.h"
|
||
|
#include "array.h"
|
||
|
|
||
|
// init
|
||
|
int init_Number(Number* number, int memory){
|
||
|
(*number).scalars=calloc(memory,sizeof(Q));
|
||
|
(*number).base=calloc(memory,sizeof(int));
|
||
|
(*number).memory=memory;
|
||
|
(*number).length=0;
|
||
|
return(0);
|
||
|
}
|
||
|
int free_Number(Number number){
|
||
|
free(number.scalars);
|
||
|
free(number.base);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// copy
|
||
|
int number_cpy(Number input, Number* output){
|
||
|
init_Number(output,input.length);
|
||
|
number_cpy_noinit(input,output);
|
||
|
return(0);
|
||
|
}
|
||
|
int number_cpy_noinit(Number input, Number* output){
|
||
|
int i;
|
||
|
if((*output).memory<input.length){
|
||
|
fprintf(stderr,"error: trying to copy a number of length %d to another with memory %d\n",input.length, (*output).memory);
|
||
|
exit(-1);
|
||
|
}
|
||
|
for(i=0;i<input.length;i++){
|
||
|
(*output).scalars[i]=input.scalars[i];
|
||
|
(*output).base[i]=input.base[i];
|
||
|
}
|
||
|
(*output).length=input.length;
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// resize memory
|
||
|
int number_resize(Number* number, int newsize){
|
||
|
Number new_number;
|
||
|
init_Number(&new_number, newsize);
|
||
|
number_cpy_noinit(*number,&new_number);
|
||
|
free_Number(*number);
|
||
|
*number=new_number;
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// add a value
|
||
|
int number_append(Q scalar, int base, Number* output){
|
||
|
if((*output).length>=(*output).memory){
|
||
|
number_resize(output,2*(*output).memory);
|
||
|
}
|
||
|
(*output).scalars[(*output).length]=scalar;
|
||
|
(*output).base[(*output).length]=base;
|
||
|
(*output).length++;
|
||
|
// not optimal
|
||
|
number_sort(*output,0,(*output).length-1);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// concatenate
|
||
|
int number_concat(Number input, Number* output){
|
||
|
int i;
|
||
|
int offset=(*output).length;
|
||
|
if((*output).length+input.length>(*output).memory){
|
||
|
// make it longer than needed by (*output).length (for speed)
|
||
|
number_resize(output,2*(*output).length+input.length);
|
||
|
}
|
||
|
for(i=0;i<input.length;i++){
|
||
|
(*output).scalars[offset+i]=input.scalars[i];
|
||
|
(*output).base[offset+i]=input.base[i];
|
||
|
}
|
||
|
(*output).length=offset+input.length;
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// special numbers
|
||
|
Number number_zero(){
|
||
|
Number ret;
|
||
|
// don't allocate 0 memory since zero's will usually be used to add to
|
||
|
init_Number(&ret,NUMBER_SIZE);
|
||
|
return(ret);
|
||
|
}
|
||
|
Number number_one(){
|
||
|
Number ret=number_zero();
|
||
|
number_add_elem(quot(1,1),1,&ret);
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
// find a base element
|
||
|
int number_find_base(int base, Number number){
|
||
|
return(intlist_find(number.base, number.length, base));
|
||
|
}
|
||
|
|
||
|
// sort
|
||
|
int number_sort(Number number, int begin, int end){
|
||
|
int i;
|
||
|
int index;
|
||
|
// the pivot: middle of the array
|
||
|
int pivot=(begin+end)/2;
|
||
|
// if the array is non trivial
|
||
|
if(begin<end){
|
||
|
// send pivot to the end
|
||
|
number_exchange_terms(pivot, end, number);
|
||
|
|
||
|
// loop over the others
|
||
|
for(i=begin, index=begin;i<end;i++){
|
||
|
// compare with pivot
|
||
|
if(number.base[i]<number.base[end]){
|
||
|
// if smaller, exchange with reference index
|
||
|
number_exchange_terms(i, index, number);
|
||
|
// move reference index
|
||
|
index++;
|
||
|
}
|
||
|
}
|
||
|
// put pivot (which we had sent to the end) in the right place
|
||
|
number_exchange_terms(index, end, number);
|
||
|
|
||
|
// recurse
|
||
|
number_sort(number, begin, index-1);
|
||
|
number_sort(number, index+1, end);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// exchange terms (for sorting)
|
||
|
int number_exchange_terms(int index1, int index2, Number number){
|
||
|
Q qtmp;
|
||
|
int tmp;
|
||
|
|
||
|
qtmp=number.scalars[index1];
|
||
|
number.scalars[index1]=number.scalars[index2];
|
||
|
number.scalars[index2]=qtmp;
|
||
|
|
||
|
tmp=number.base[index1];
|
||
|
number.base[index1]=number.base[index2];
|
||
|
number.base[index2]=tmp;
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// checks whether two numbers are equal
|
||
|
// requires both numbers to be sorted
|
||
|
int number_compare(Number x1, Number x2){
|
||
|
int i;
|
||
|
if(x1.length!=x2.length){
|
||
|
return(0);
|
||
|
}
|
||
|
for(i=0;i<x1.length;i++){
|
||
|
if(x1.base[i]!=x2.base[i] || Q_cmp(x1.scalars[i],x2.scalars[i])!=0){
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
// add (write result to second element)
|
||
|
int number_add_chain(Number input, Number* inout){
|
||
|
int i;
|
||
|
for(i=0;i<input.length;i++){
|
||
|
number_add_elem(input.scalars[i], input.base[i], inout);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
// add a single element
|
||
|
int number_add_elem(Q scalar, int base, Number* inout){
|
||
|
int index;
|
||
|
index=number_find_base(base,*inout);
|
||
|
if(index>=0){
|
||
|
(*inout).scalars[index]=Q_add((*inout).scalars[index], scalar);
|
||
|
}
|
||
|
else{
|
||
|
number_append(scalar, base, inout);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
// create a new number
|
||
|
int number_add(Number x1, Number x2, Number* out){
|
||
|
number_cpy(x1,out);
|
||
|
number_add_chain(x2,out);
|
||
|
return(0);
|
||
|
}
|
||
|
// return the number
|
||
|
Number number_add_ret(Number x1, Number x2){
|
||
|
Number out;
|
||
|
number_add(x1,x2,&out);
|
||
|
return(out);
|
||
|
}
|
||
|
|
||
|
// multiply
|
||
|
int number_prod(Number x1, Number x2, Number* out){
|
||
|
int i,j;
|
||
|
int div;
|
||
|
Q new_scalar;
|
||
|
int new_base;
|
||
|
init_Number(out, x1.length);
|
||
|
for(i=0;i<x1.length;i++){
|
||
|
for(j=0;j<x2.length;j++){
|
||
|
new_scalar=Q_prod(x1.scalars[i], x2.scalars[j]);
|
||
|
// simplify the base
|
||
|
div=gcd(x1.base[i], x2.base[j]);
|
||
|
new_base=(x1.base[i]/div)*(x2.base[j]/div);
|
||
|
new_scalar.numerator*=div;
|
||
|
|
||
|
number_add_elem(new_scalar, new_base, out);
|
||
|
}
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
// write to second number
|
||
|
int number_prod_chain(Number input, Number* inout){
|
||
|
Number tmp;
|
||
|
number_prod(input,*inout,&tmp);
|
||
|
free_Number(*inout);
|
||
|
*inout=tmp;
|
||
|
return(0);
|
||
|
}
|
||
|
// return result
|
||
|
Number number_prod_ret(Number x1, Number x2){
|
||
|
Number ret;
|
||
|
number_prod(x1,x2,&ret);
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
// multiply by a rational
|
||
|
int number_Qprod_chain(Q q, Number* inout){
|
||
|
int i;
|
||
|
for(i=0;i<(*inout).length;i++){
|
||
|
(*inout).scalars[i]=Q_prod(q,(*inout).scalars[i]);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
// write to output
|
||
|
int number_Qprod(Q q, Number x, Number* inout){
|
||
|
number_cpy(x,inout);
|
||
|
number_Qprod_chain(q,inout);
|
||
|
return(0);
|
||
|
}
|
||
|
// return result
|
||
|
Number number_Qprod_ret(Q q, Number x){
|
||
|
Number ret;
|
||
|
number_Qprod(q,x,&ret);
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
// inverse
|
||
|
int number_inverse_inplace(Number* inout){
|
||
|
int i;
|
||
|
for(i=0;i<(*inout).length;i++){
|
||
|
if((*inout).base[i]>0){
|
||
|
(*inout).scalars[i]=Q_inverse((*inout).scalars[i]);
|
||
|
(*inout).scalars[i].denominator*=(*inout).base[i];
|
||
|
}
|
||
|
else if((*inout).base[i]<0){
|
||
|
(*inout).scalars[i]=Q_inverse((*inout).scalars[i]);
|
||
|
(*inout).scalars[i].denominator*=-(*inout).base[i];
|
||
|
(*inout).scalars[i].numerator*=-1;
|
||
|
}
|
||
|
else{
|
||
|
fprintf(stderr,"error: attempting to invert 0\n");
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
// write to output
|
||
|
int number_inverse(Number input, Number* output){
|
||
|
number_cpy(input,output);
|
||
|
number_inverse_inplace(output);
|
||
|
return(0);
|
||
|
}
|
||
|
// return result
|
||
|
Number number_inverse_ret(Number x){
|
||
|
Number ret;
|
||
|
number_inverse(x,&ret);
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
// quotient
|
||
|
int number_quot(Number x1, Number x2, Number* output){
|
||
|
Number inv;
|
||
|
number_inverse(x2, &inv);
|
||
|
number_prod(x1, inv, output);
|
||
|
free_Number(inv);
|
||
|
return(0);
|
||
|
}
|
||
|
int number_quot_chain(Number x1, Number* inout){
|
||
|
number_inverse_inplace(inout);
|
||
|
number_prod_chain(x1, inout);
|
||
|
return(0);
|
||
|
}
|
||
|
Number number_quot_ret(Number x1, Number x2){
|
||
|
Number ret;
|
||
|
number_quot(x1, x2, &ret);
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
|
||
|
// remove 0's
|
||
|
int number_simplify(Number in, Number* out){
|
||
|
int i;
|
||
|
init_Number(out, in.length);
|
||
|
for(i=0;i<in.length;i++){
|
||
|
if(in.scalars[i].numerator!=0){
|
||
|
number_append(in.scalars[i],in.base[i], out);
|
||
|
}
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// check whether a number is 0
|
||
|
int number_is_zero(Number x){
|
||
|
int i;
|
||
|
for(i=0;i<x.length;i++){
|
||
|
if(x.scalars[i].numerator!=0 && x.base[i]!=0){
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
// approximate numerical expression
|
||
|
long double number_double_val(Number x){
|
||
|
int i;
|
||
|
long double ret=0.;
|
||
|
long double b;
|
||
|
for(i=0;i<x.length;i++){
|
||
|
if(x.scalars[i].numerator!=0){
|
||
|
b=1.0*x.base[i];
|
||
|
ret+=Q_double_value(x.scalars[i])*sqrt(b);
|
||
|
}
|
||
|
}
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
|
||
|
// print to string
|
||
|
int number_sprint(Number number, Char_Array* out){
|
||
|
int i;
|
||
|
Number simp;
|
||
|
number_simplify(number, &simp);
|
||
|
for(i=0;i<simp.length;i++){
|
||
|
if(i>0){
|
||
|
char_array_snprintf(out," + ");
|
||
|
}
|
||
|
if(simp.length>1 || (simp.length==1 && simp.base[0]!=1)){
|
||
|
char_array_append('(',out);
|
||
|
}
|
||
|
Q_sprint(simp.scalars[i], out);
|
||
|
if(simp.length>1 || (simp.length==1 && simp.base[0]!=1)){
|
||
|
char_array_append(')',out);
|
||
|
}
|
||
|
|
||
|
if(simp.base[i]!=1){
|
||
|
char_array_snprintf(out,"s{%d}",simp.base[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free_Number(simp);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// print to stdout
|
||
|
int number_print(Number number){
|
||
|
Char_Array buffer;
|
||
|
init_Char_Array(&buffer,5*number.length);
|
||
|
number_sprint(number, &buffer);
|
||
|
printf("%s",buffer.str);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
#define PP_NULL_MODE 0
|
||
|
#define PP_NUM_MODE 1
|
||
|
#define PP_SQRT_MODE 2
|
||
|
// read from a string
|
||
|
int str_to_Number(char* str, Number* number){
|
||
|
char* ptr;
|
||
|
int mode;
|
||
|
char* buffer=calloc(str_len(str)+1,sizeof(char));
|
||
|
char* buffer_ptr=buffer;
|
||
|
Q num;
|
||
|
int base;
|
||
|
// whether there are parentheses in the string
|
||
|
int exist_parenthesis=0;
|
||
|
|
||
|
init_Number(number, NUMBER_SIZE);
|
||
|
|
||
|
// init num and base
|
||
|
// init to 0 so that if str is empty, then the number is set to 0
|
||
|
num=quot(0,1);
|
||
|
base=1;
|
||
|
|
||
|
mode=PP_NULL_MODE;
|
||
|
for(ptr=str;*ptr!='\0';ptr++){
|
||
|
switch(*ptr){
|
||
|
// read number
|
||
|
case '(':
|
||
|
if(mode==PP_NULL_MODE){
|
||
|
// init base
|
||
|
base=1;
|
||
|
mode=PP_NUM_MODE;
|
||
|
exist_parenthesis=1;
|
||
|
}
|
||
|
break;
|
||
|
case ')':
|
||
|
if(mode==PP_NUM_MODE){
|
||
|
str_to_Q(buffer,&num);
|
||
|
buffer_ptr=buffer;
|
||
|
*buffer_ptr='\0';
|
||
|
mode=PP_NULL_MODE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// read sqrt
|
||
|
case '{':
|
||
|
// init num
|
||
|
if(num.numerator==0){
|
||
|
num=quot(1,1);
|
||
|
}
|
||
|
if(mode==PP_NULL_MODE){
|
||
|
mode=PP_SQRT_MODE;
|
||
|
}
|
||
|
// if there is a square root, then do not read a fraction (see end of loop)
|
||
|
exist_parenthesis=1;
|
||
|
break;
|
||
|
case '}':
|
||
|
if(mode==PP_SQRT_MODE){
|
||
|
sscanf(buffer,"%d",&base);
|
||
|
buffer_ptr=buffer;
|
||
|
*buffer_ptr='\0';
|
||
|
mode=PP_NULL_MODE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// write num
|
||
|
case '+':
|
||
|
if(mode==PP_NULL_MODE){
|
||
|
number_add_elem(num, base, number);
|
||
|
// re-init num and base
|
||
|
num=quot(0,1);
|
||
|
base=1;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if(mode!=PP_NULL_MODE){
|
||
|
buffer_ptr=str_addchar(buffer_ptr,*ptr);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// last step
|
||
|
if(mode==PP_NULL_MODE){
|
||
|
if(exist_parenthesis==0){
|
||
|
str_to_Q(str, &num);
|
||
|
}
|
||
|
number_add_elem(num, base, number);
|
||
|
}
|
||
|
|
||
|
free(buffer);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// with Char_Array input
|
||
|
int char_array_to_Number(Char_Array cstr_num,Number* output){
|
||
|
char* buffer;
|
||
|
char_array_to_str(cstr_num,&buffer);
|
||
|
str_to_Number(buffer, output);
|
||
|
free(buffer);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// -------------------- Number_Matrix ---------------------
|
||
|
|
||
|
// init
|
||
|
int init_Number_Matrix(Number_Matrix* matrix, int length){
|
||
|
int i,j;
|
||
|
(*matrix).matrix=calloc(length,sizeof(Number*));
|
||
|
(*matrix).indices=calloc(length,sizeof(int));
|
||
|
for(i=0;i<length;i++){
|
||
|
(*matrix).matrix[i]=calloc(length,sizeof(Number));
|
||
|
for(j=0;j<length;j++){
|
||
|
(*matrix).matrix[i][j]=number_zero();
|
||
|
}
|
||
|
}
|
||
|
(*matrix).length=length;
|
||
|
return(0);
|
||
|
}
|
||
|
int free_Number_Matrix(Number_Matrix matrix){
|
||
|
int i,j;
|
||
|
for(i=0;i<matrix.length;i++){
|
||
|
for(j=0;j<matrix.length;j++){
|
||
|
free_Number(matrix.matrix[i][j]);
|
||
|
}
|
||
|
free(matrix.matrix[i]);
|
||
|
}
|
||
|
free(matrix.matrix);
|
||
|
free(matrix.indices);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// Pauli matrices
|
||
|
int Pauli_matrix(int i, Number_Matrix* output){
|
||
|
init_Number_Matrix(output,2);
|
||
|
switch(i){
|
||
|
case 1:
|
||
|
number_add_elem(quot(1,1),1,(*output).matrix[0]+1);
|
||
|
number_add_elem(quot(1,1),1,(*output).matrix[1]+0);
|
||
|
break;
|
||
|
case 2:
|
||
|
number_add_elem(quot(-1,1),-1,(*output).matrix[0]+1);
|
||
|
number_add_elem(quot(1,1),-1,(*output).matrix[1]+0);
|
||
|
break;
|
||
|
case 3:
|
||
|
number_add_elem(quot(1,1),1,(*output).matrix[0]+0);
|
||
|
number_add_elem(quot(-1,1),1,(*output).matrix[1]+1);
|
||
|
break;
|
||
|
default:
|
||
|
fprintf(stderr,"error: requested %d-th pauli matrix\n",i);
|
||
|
exit(-1);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|