diff options
Diffstat (limited to 'src/coefficient.c')
-rw-r--r-- | src/coefficient.c | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/src/coefficient.c b/src/coefficient.c new file mode 100644 index 0000000..c26b668 --- /dev/null +++ b/src/coefficient.c @@ -0,0 +1,739 @@ +/* +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 "coefficient.h" + +#include <stdio.h> +#include <stdlib.h> +#include "definitions.cpp" +#include "rational.h" +#include "istring.h" +#include "array.h" +#include "number.h" +#include "tools.h" + + +// allocate memory +int init_Coefficient(Coefficient* coef,int size){ + (*coef).factors=calloc(size,sizeof(Int_Array)); + (*coef).nums=calloc(size,sizeof(Number)); + (*coef).denoms=calloc(size,sizeof(coef_denom)); + (*coef).length=0; + (*coef).memory=size; + + return(0); +} + +// free memory +int free_Coefficient(Coefficient coef){ + int i; + for(i=0;i<coef.length;i++){ + free_Int_Array(coef.factors[i]); + free_Number(coef.nums[i]); + } + free(coef.factors); + free(coef.nums); + free(coef.denoms); + + return(0); +} + +// copy a coefficient +int coefficient_cpy(Coefficient input, Coefficient* output){ + init_Coefficient(output,input.length); + coefficient_cpy_noinit(input,output); + return(0); +} +int coefficient_cpy_noinit(Coefficient input, Coefficient* output){ + int i; + + // if output does not have enough memory allocated to it + if(input.length>(*output).memory){ + resize_Coefficient(output,input.length); + } + + for(i=0;i<input.length;i++){ + int_array_cpy(input.factors[i],(*output).factors+i); + number_cpy(input.nums[i],(*output).nums+i); + (*output).denoms[i]=input.denoms[i]; + } + (*output).length=input.length; + return(0); +} + + +// resize the memory allocated to a coefficient +int resize_Coefficient(Coefficient* coefficient,int new_size){ + Coefficient new_coef; + int i; + + init_Coefficient(&new_coef,new_size); + for(i=0;i<(*coefficient).length;i++){ + new_coef.factors[i]=(*coefficient).factors[i]; + new_coef.nums[i]=(*coefficient).nums[i]; + new_coef.denoms[i]=(*coefficient).denoms[i]; + } + new_coef.length=(*coefficient).length; + + free((*coefficient).factors); + free((*coefficient).nums); + free((*coefficient).denoms); + + *coefficient=new_coef; + return(0); +} + + +// append an element to a coefficient +int coefficient_append(Int_Array factor,Number num, coef_denom denom, Coefficient* output){ + int offset=(*output).length; + + if((*output).length>=(*output).memory){ + resize_Coefficient(output,2*(*output).memory+1); + } + // copy and allocate + int_array_cpy(factor,(*output).factors+offset); + number_cpy(num,(*output).nums+offset); + (*output).denoms[offset]=denom; + // increment length + (*output).length++; + return(0); +} +// append an element to a coefficient without allocating memory +int coefficient_append_noinit(Int_Array factor, Number num, coef_denom denom, Coefficient* output){ + int offset=(*output).length; + + if((*output).length>=(*output).memory){ + resize_Coefficient(output,2*(*output).memory+1); + } + // copy without allocating + (*output).factors[offset]=factor; + (*output).nums[offset]=num; + (*output).denoms[offset]=denom; + // increment length + (*output).length++; + return(0); +} + +// concatenate coefficients and simplify result +int coefficient_concat(Coefficient input, Coefficient* output){ + int i; + for(i=0;i<input.length;i++){ + coefficient_append(input.factors[i],input.nums[i],input.denoms[i],output); + } + + coefficient_simplify(output); + return(0); +} +int coefficient_concat_noinit(Coefficient input, Coefficient* output){ + int i; + for(i=0;i<input.length;i++){ + coefficient_append_noinit(input.factors[i],input.nums[i],input.denoms[i],output); + } + + coefficient_simplify(output); + + // free input arrays + free(input.factors); + free(input.nums); + free(input.denoms); + return(0); +} + + +// simplify a Coefficient +int coefficient_simplify(Coefficient* coefficient){ + int i; + Coefficient output; + init_Coefficient(&output,(*coefficient).length); + // the combination of numerical factors + Number new_num; + init_Number(&new_num,NUMBER_SIZE); + + // sort the factors in the coefficient + for(i=0;i<(*coefficient).length;i++){ + int_array_sort((*coefficient).factors[i],0,(*coefficient).factors[i].length-1); + } + // in order to perform a simplification, the list of terms must be + // sorted (so that terms that are proportional are next to each other) + sort_coefficient(coefficient,0,(*coefficient).length-1); + + for(i=0;i<(*coefficient).length;i++){ + // if the term actually exists + if(number_is_zero((*coefficient).nums[i])!=1){ + // combine numerical factors + number_add_chain((*coefficient).nums[i],&new_num); + } + // if the number is 0, the previous terms that may have the same factors should still be added, hence the 'if' ends here + + // if the factor is different from the next then add term + if(i==(*coefficient).length-1 || (int_array_cmp((*coefficient).factors[i],(*coefficient).factors[i+1])!=0) || coef_denom_cmp((*coefficient).denoms[i],(*coefficient).denoms[i+1])!=0){ + // check that the coefficient is not trivial + if(number_is_zero(new_num)!=1){ + coefficient_append((*coefficient).factors[i],new_num,(*coefficient).denoms[i],&output); + } + + // reset new numerical factor + free_Number(new_num); + init_Number(&new_num,NUMBER_SIZE); + } + } + + free_Number(new_num); + free_Coefficient(*coefficient); + *coefficient=output; + return(0); +} + +// sort the terms in an equation (quicksort algorithm) +int sort_coefficient(Coefficient* coefficient, 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 + exchange_coefficient_terms(pivot,end,coefficient); + // loop over the others + for(i=begin, index=begin;i<end;i++){ + // compare with pivot + if(coef_denom_cmp((*coefficient).denoms[i],(*coefficient).denoms[end])<0 || ( coef_denom_cmp((*coefficient).denoms[i],(*coefficient).denoms[end])==0 && (int_array_cmp((*coefficient).factors[i],(*coefficient).factors[end])<0)) ){ + // if smaller, exchange with reference index + exchange_coefficient_terms(i,index,coefficient); + // move reference index + index++; + } + } + // put pivot (which we had sent to the end) in the right place + exchange_coefficient_terms(index,end,coefficient); + // recurse + sort_coefficient(coefficient, begin, index-1); + sort_coefficient(coefficient, index+1, end); + } + return(0); +} + +// exchange two terms (for the sorting algorithm) +int exchange_coefficient_terms(int i, int j, Coefficient* coefficient){ + Int_Array ptmp; + Number tmpq; + coef_denom tmpc; + + ptmp=(*coefficient).factors[j]; + (*coefficient).factors[j]=(*coefficient).factors[i]; + (*coefficient).factors[i]=ptmp; + + tmpq=(*coefficient).nums[j]; + (*coefficient).nums[j]=(*coefficient).nums[i]; + (*coefficient).nums[i]=tmpq; + + tmpc=(*coefficient).denoms[j]; + (*coefficient).denoms[j]=(*coefficient).denoms[i]; + (*coefficient).denoms[i]=tmpc; + return(0); +} + +// derive a coefficient with respect to an index +int coefficient_deriv_noinit(Coefficient input, int index, Coefficient* output){ + int i,j; + // temp list of indices + Int_Array factor; + // number of times index was found + int match_count; + // whether the output contains at least one factor + int at_least_one=0; + coef_denom denom; + + // loop over monomials + for(i=0;i<input.length;i++){ + init_Int_Array(&factor,input.factors[i].length); + // init match count + match_count=0; + // loop over indices + for(j=0;j<input.factors[i].length;j++){ + // if found + if(input.factors[i].values[j]==index){ + // if it's the first match, don't add it + if(match_count!=0){ + int_array_append(index,&factor); + } + match_count++; + } + // add the index + else{ + int_array_append(input.factors[i].values[j],&factor); + } + } + + denom=input.denoms[i]; + // if the index is that of 1/C + if(index==input.denoms[i].index){ + // if no C in the numerator (which is normal behavior) + if(match_count==0){ + denom.power++; + } + match_count-=input.denoms[i].power; + } + + + // if the derivative doesn't vanish, add it to the coefficient + if(match_count!=0){ + at_least_one=1; + coefficient_append_noinit(factor,number_Qprod_ret(quot(match_count,1),input.nums[i]), denom, output); + } + else{ + free_Int_Array(factor); + } + } + + if(at_least_one==1){ + coefficient_simplify(output); + } + else{ + // add a trivial element to the coefficient + init_Int_Array(&factor,0); + denom.index=-1; + denom.power=0; + coefficient_append_noinit(factor,number_zero(),denom,output); + } + + return(0); +} + +int coefficient_deriv(Coefficient input, int index, Coefficient* output){ + init_Coefficient(output, COEF_SIZE); + coefficient_deriv_noinit(input, index, output); + return(0); +} + +/* +// derive a coefficient with respect to an index (as a polynomial) (does not derive the 1/(1+C)^p ) +int coefficient_deriv_noinit(Coefficient input, int index, Coefficient* output){ + int i; + // temp list of indices + Int_Array factor; + // number of times index was found + int match_count; + // whether the output contains at least one factor + int at_least_one=0; + coef_denom denom; + + // loop over monomials + for(i=0;i<input.length;i++){ + // derivative of monomial + monomial_deriv(input.factors[i], index, &factor, &match_count); + + // if the derivative doesn't vanish, add it to the coefficient + if(match_count>0){ + at_least_one=1; + coefficient_append_noinit(factor,number_Qprod_ret(quot(match_count,1),input.nums[i]), input.denoms[i],output); + } + else{ + free_Int_Array(factor); + } + } + + if(at_least_one>0){ + coefficient_simplify(output); + } + else{ + // add a trivial element to the coefficient + init_Int_Array(&factor,0); + denom.index=-1; + denom.power=0; + coefficient_append_noinit(factor,number_zero(),denom,output); + } + + return(0); +} + +// derive a monomial with respect to an index +int monomial_deriv(Int_Array factor, int index, Int_Array* out_factor, int* match_count){ + int j; + + init_Int_Array(out_factor,factor.length); + // init match count + *match_count=0; + + // loop over indices + for(j=0;j<factor.length;j++){ + // if found + if(factor.values[j]==index){ + // if it's the first match, don't add it + if(*match_count!=0){ + int_array_append(index,out_factor); + } + (*match_count)++; + } + // add the index + else{ + int_array_append(factor.values[j],out_factor); + } + } + + return(0); +} +*/ + + + +// product of two coefficients +int coefficient_prod(Coefficient coef1, Coefficient coef2, Coefficient* output){ + int i,j; + // tmp factor + Int_Array factor; + coef_denom denom; + + // init + init_Coefficient(output,COEF_SIZE); + + // loop over coef1 + for(i=0;i<coef1.length;i++){ + // loop over coef2 + for(j=0;j<coef2.length;j++){ + init_Int_Array(&factor,coef1.factors[i].length+coef2.factors[j].length); + int_array_concat(coef1.factors[i],&factor); + int_array_concat(coef2.factors[j],&factor); + + // don't throw an error if the power is 0 + if(coef2.denoms[i].power==0){ + coef2.denoms[i].index=coef1.denoms[i].index; + } + else if(coef1.denoms[i].power==0){ + coef1.denoms[i].index=coef2.denoms[i].index; + } + if(coef1.denoms[i].index!=coef2.denoms[j].index){ + fprintf(stderr,"error: cannot multiply flow equations with different constants\n"); + exit(-1); + } + denom=coef1.denoms[i]; + denom.power+=coef2.denoms[j].power; + coefficient_append_noinit(factor,number_prod_ret(coef1.nums[i],coef2.nums[j]), denom, output); + } + } + + // simplify output + coefficient_simplify(output); + return(0); +} + +// product of coefficients, output replaces the second coefficient +int coefficient_prod_chain(Coefficient in, Coefficient* inout){ + Coefficient tmp_coef; + coefficient_prod(in,*inout,&tmp_coef); + free_Coefficient(*inout); + *inout=tmp_coef; + return(0); +} + + +// print coefficient +// offset specifies the amount of blank space to the left of the terms after the first +// prepend indices by ind_pre +int coefficient_sprint(Coefficient coef, Char_Array* output, int offset, char index_pre){ + Char_Array buffer; + int i,j,k; + int dcount; + + if(coef.length==0){ + char_array_snprintf(output, " (0)\n"); + } + + for(i=0;i<coef.length;i++){ + if(i==0){ + char_array_snprintf(output, " "); + } + else{ + for(j=0;j<=offset;j++){ + char_array_append(' ',output); + } + char_array_append('+',output); + } + + // print numerical coefficient + char_array_append('(',output); + init_Char_Array(&buffer, STR_SIZE); + number_sprint(coef.nums[i], &buffer); + char_array_concat(buffer, output); + free_Char_Array(buffer); + char_array_append(')',output); + + // print factors + for(j=0;j<coef.factors[i].length;j++){ + // constant indices + if(coef.factors[i].values[j]<0){ + // count derivatives + dcount=-coef.factors[i].values[j]/DOFFSET; + char_array_append('[',output); + for(k=0;k<dcount;k++){ + char_array_append('d',output); + } + char_array_snprintf(output,"C%d]",-coef.factors[i].values[j]-dcount*DOFFSET); + } + else{ + // count derivatives + dcount=coef.factors[i].values[j]/DOFFSET; + char_array_append('[',output); + for(k=0;k<dcount;k++){ + char_array_append('d',output); + } + char_array_snprintf(output,"%c%d]",index_pre,coef.factors[i].values[j]-dcount*DOFFSET); + } + } + + // print constant denominators + if(coef.denoms[i].power!=0){ + char_array_snprintf(output,"[/C%d^%d]",-coef.denoms[i].index,coef.denoms[i].power); + } + + char_array_append('\n',output); + } + + return(0); +} + + +// read from a string +#define PP_NULL_MODE 0 +#define PP_BRACKET_MODE 1 +#define PP_INDICES_MODE 2 +#define PP_POWER_MODE 3 +#define PP_COMMENT_MODE 4 +#define PP_NUMBER_MODE 5 +#define PP_CONSTANT_MODE 6 +#define PP_CONSTANT_DENOM_MODE 7 +int char_array_to_Coefficient(Char_Array str_coef, Coefficient* output){ + // buffer + char* buffer=calloc(str_coef.length+1,sizeof(char)); + char* buffer_ptr=buffer; + Int_Array indices; + coef_denom denom; + Number num, tmp1_num; + int mode; + int i,j; + int parenthesis_count=0; + int dcount=0; + + // allocate memory + init_Coefficient(output,COEF_SIZE); + + // init + init_Int_Array(&indices, MONOMIAL_SIZE); + num=number_one(); + denom.index=-1; + denom.power=0; + + *buffer_ptr='\0'; + // loop over the input polynomial + // start in null mode + mode=PP_NULL_MODE; + for(j=0;j<str_coef.length;j++){ + if(mode==PP_COMMENT_MODE){ + if(str_coef.str[j]=='\n'){ + mode=PP_NULL_MODE; + } + } + else{ + switch(str_coef.str[j]){ + // new indices + case '+': + if(mode==PP_NULL_MODE){ + coefficient_append_noinit(indices, num, denom, output); + // reset indices, num + init_Int_Array(&indices, MONOMIAL_SIZE); + num=number_one(); + denom.index=-1; + denom.power=0; + } + break; + + // enter indices or power mode + case '[': + if(mode==PP_NULL_MODE){ + mode=PP_BRACKET_MODE; + // reset derivatives count + dcount=0; + } + break; + // indices mode + case '%': + if(mode==PP_BRACKET_MODE){ + mode=PP_INDICES_MODE; + buffer_ptr=buffer; + *buffer_ptr='\0'; + } + break; + case 'C': + if(mode==PP_BRACKET_MODE){ + mode=PP_CONSTANT_MODE; + buffer_ptr=buffer; + *buffer_ptr='\0'; + } + break; + case '/': + if(mode==PP_BRACKET_MODE){ + mode=PP_CONSTANT_DENOM_MODE; + buffer_ptr=buffer; + *buffer_ptr='\0'; + } + else if(mode!=PP_NULL_MODE){ + // write to buffer + buffer_ptr=str_addchar(buffer_ptr,str_coef.str[j]); + } + break; + // derivatives + case 'd': + if(mode==PP_BRACKET_MODE || mode==PP_INDICES_MODE || mode==PP_CONSTANT_MODE){ + dcount++; + } + break; + // power mode + case '^': + if(mode==PP_CONSTANT_DENOM_MODE){ + sscanf(buffer,"%d",&i); + denom.index=-i; + mode=PP_POWER_MODE; + buffer_ptr=buffer; + *buffer_ptr='\0'; + } + else{ + buffer_ptr=str_addchar(buffer_ptr,str_coef.str[j]); + } + break; + // read indices or power + case ']': + sscanf(buffer,"%d",&i); + if(mode==PP_INDICES_MODE){ + int_array_append(i+dcount*DOFFSET,&indices); + } + else if(mode==PP_CONSTANT_MODE){ + int_array_append(-i-dcount*DOFFSET,&indices); + } + else if(mode==PP_POWER_MODE){ + denom.power=i; + } + // switch back to null mode + mode=PP_NULL_MODE; + break; + + // numerical pre-factor + case '(': + if(mode==PP_NULL_MODE){ + mode=PP_NUMBER_MODE; + parenthesis_count=0; + buffer_ptr=buffer; + *buffer_ptr='\0'; + } + else if(mode==PP_NUMBER_MODE){ + // match parentheses + parenthesis_count++; + buffer_ptr=str_addchar(buffer_ptr,str_coef.str[j]); + } + break; + case ')': + if(mode==PP_NUMBER_MODE){ + if(parenthesis_count==0){ + // write num + str_to_Number(buffer,&tmp1_num); + number_prod_chain(tmp1_num,&num); + free_Number(tmp1_num); + // back to null mode + mode=PP_NULL_MODE; + } + else{ + parenthesis_count--; + buffer_ptr=str_addchar(buffer_ptr,str_coef.str[j]); + } + } + break; + + // characters to ignore + case ' ':break; + case '&':break; + case '\n':break; + + // comments + case '#': + mode=PP_COMMENT_MODE; + break; + + default: + if(mode!=PP_NULL_MODE){ + // write to buffer + buffer_ptr=str_addchar(buffer_ptr,str_coef.str[j]); + } + break; + } + } + } + + // last term + coefficient_append_noinit(indices, num, denom, output); + + free(buffer); + return(0); +} + +int str_to_Coefficient(char* str, Coefficient* output){ + Char_Array array; + array.length=str_len(str); + array.str=str; + char_array_to_Coefficient(array, output); + return(0); +} + +// compare coefficient denominators +int coef_denom_cmp(coef_denom denom1, coef_denom denom2){ + if(denom1.index<denom2.index){ + return(1); + } + else if(denom1.index>denom2.index){ + return(-1); + } + + if(denom1.power<denom2.power){ + return(-1); + } + else if(denom1.power>denom2.power){ + return(1); + } + + return(0); +} + + +// evaluate a coefficient on a vector +int evalcoef(RCC rccs, Coefficient coef, long double* out){ + int i,j; + long double num_factor; + + *out=0; + + // for each monomial + for(i=0;i<coef.length;i++){ + // product of factors + for(j=0, num_factor=1.;j<coef.factors[i].length;j++){ + num_factor*=rccs.values[intlist_find_err(rccs.indices,rccs.length,coef.factors[i].values[j])]; + } + // denominator + if(coef.denoms[i].power>0){ + num_factor/=dpower(rccs.values[intlist_find_err(rccs.indices,rccs.length,coef.denoms[i].index)],coef.denoms[i].power); + } + *out+=num_factor*number_double_val(coef.nums[i]); + } + return(0); +} |