R/free.R

Defines functions `[<-.freealg` `[.freealg` `keep_pos` `all_pos` `abelianize` `inv` `nterms` `deg` `grade<-` `grades` `grade` `pepper` `linear` `subs` `subsu` `horner` `deriv.freealg` `natural_char_to_freealg` `char_to_freealg` `string_to_freealg` `vector_to_free` `print.freealg` `rfalggg` `rfalgg` `rfalg` `is_ok_free` `is.freealg` `constant<-.freealg` `constant.freealg` `constant.numeric` `is.constant` `is.zero` `numeric_to_free` `as.freealg` `coeffs<-.freealg` `coeffs<-` `coeffs` `words` `freealg`

`freealg` <- function(words,coeffs){ # formal
  if(missing(coeffs)){coeffs <- 1}
  if(length(coeffs) == 1){coeffs <- rep(coeffs,length(words))}
  stopifnot(is_ok_free(words,coeffs))
  out <- lowlevel_simplify(words,coeffs)  # simplify() is defined in
                                 # RcppExports.R; it returns a list

  class(out) <- "freealg"   # this is the only time class() is set to "freealg"
  return(out)
}

`words` <- function(x){disord(x[[1]],hashcal(x))}
`coeffs` <- function(x,drop=TRUE){disord(x[[2]],hashcal(x),drop=drop)} # accessor methods end here

`coeffs<-` <- function(x,value){UseMethod("coeffs<-")}
`coeffs<-.freealg` <- function(x,value){
  if(is.zero(x)){return(x)}
  jj <- coeffs(x,drop=FALSE)
  if(is.disord(value)){
    stopifnot(consistent(words(x),value))
    jj <- value
  } else {
    jj[] <- value  # the meat
  }
  freealg(words(x),jj)
}

`as.freealg` <- function(x,...){
  if(is.freealg(x)){
    return(x)
  } else if(is.list(x)){
    return(freealg(x[[1]],x[[2]]))
  } else if(is.numeric(x) &&(length(x)==1)){
    return(numeric_to_free(x))
  } else if(is.numeric(x) &&(length(x) > 1)){
    return(vector_to_free(x))
  } else if(is.character(x)){
    return(natural_char_to_freealg(x))
  } else {
    stop("not recognised")
  }
}

`numeric_to_free` <- function(x){
  stopifnot(length(x)==1)
  freealg(list(numeric(0)),x)
  }

`is.zero` <- function(x){
  if(!is.freealg(x)){ return(x==0)}
  return(length(coeffs(x))==0)
}

`is.constant` <- function(x){
  if(!is.freealg(x)){
    return(is.numeric(x) & (length(x)==1))
  } else {
    if(is.zero(x)){
      return(TRUE)
    } else {
      jj <- elements(words(x))
      return((length(jj)==1) & identical(jj[[1]],integer(0)))
    }
  }
}

"constant" <- function(x){UseMethod("constant")}
"constant<-" <- function(x, value){UseMethod("constant<-")}

`constant.numeric` <- function(x){numeric_to_free(x)}

`constant.freealg` <- function(x){
  wanted <- sapply(words(x),function(x){length(x)==0})
  if(any(wanted)){
    out <- coeffs(x)[wanted]
  } else {
    out <- 0
  }
  return(out)
}

`constant<-.freealg` <- function(x,value){
  wanted <- sapply(words(x),function(x){length(x)==0})
  if(any(wanted)){
    co <- coeffs(x)
    co[wanted] <- value
    w <- elements(words(x))
    } else {
      co <- c(elements(coeffs(x)),value)
      w <- c(elements(words(x)),list(numeric(0)))
    }
  freealg(elements(w),elements(co))
}

`is.freealg` <- function(x){inherits(x,"freealg")}

`is_ok_free` <- function(words,coeffs){
    if(is.disord(words) | is.disord(coeffs)){
        stopifnot(disordR::consistent(words,coeffs))
    }
    
    if( (length(words)==0) && (length(coeffs)==0)){
        return(TRUE)  # zero element
    }

    if(identical(words,list()) && length(coeffs)==1){
      return(TRUE)
      }
    stopifnot(unlist(lapply(elements(words),is.numeric)))
    stopifnot(is.numeric(coeffs))

    stopifnot(length(words)==length(coeffs))
    return(TRUE)
}

`rfalg` <- function(n=7, distinct=3, maxsize=4, include.negative=FALSE){
  distinct <- seq_len(distinct)
  if(include.negative){distinct <- c(distinct,-distinct)}
  freealg(replicate(n,sample(distinct,min(1+rgeom(1,1/maxsize),maxsize),replace=TRUE),simplify=FALSE), seq_len(n))
}

`rfalgg` <- function(n=30, distinct=8, maxsize=7, include.negative=FALSE){
    rfalg(n=n, distinct=distinct, maxsize=maxsize, include.negative=FALSE)
}

`rfalggg` <- function(n=100, distinct=26, maxsize=30, include.negative=FALSE){
    rfalg(n=n, distinct=distinct, maxsize=maxsize, include.negative=FALSE)
}


`print.freealg` <- function(x,...){
  cat("free algebra element algebraically equal to\n")
  SHRT_MAX <- 32767
  SHRT_MAXo2 <- round(SHRT_MAX/2)
  

  if(isTRUE(getOption("usecaret"))){
      symbols <- c(letters,paste(letters,"^-1",sep=""))
  } else {
      symbols <- c(letters,LETTERS)
  }
  n <- 26
  
  out <- ""
  w <- elements(words(x))
  eco <- elements(coeffs(x))
  for(i in seq_along(w)){
    co <- eco[i]
    if(co>0){
      pm <- " + " # pm = plus or minus
    } else {
      pm <- " - "
    }
    jj <- w[i][[1]]
    co <- capture.output(cat(abs(co)))
    if(length(jj)>0){mulsym <- getOption("mulsym")} else {mulsym <- ""}
    if((co=="1") && (is.null(mulsym) || nchar(mulsym)==0) && (length(jj)>0)){co <- ""}

    if(any(jj<0)){jj[jj<0] <- n-jj[jj<0]}
    ss <- symbols[jj]
    wanted <- jj>SHRT_MAX
    if(any(wanted)){# (da)
        ss[wanted] <- paste("(d",symbols[jj[wanted]-SHRT_MAX],")",sep="")
    }

    wanted <- (jj>SHRT_MAXo2) & (jj<SHRT_MAX) # (dA)
    if(any(wanted)){
        ss[wanted] <- paste("(d",symbols[26-jj[wanted]+SHRT_MAX],")",sep="")
    }

    ss <- paste(ss,collapse="")
    out <- paste(out, pm, co, mulsym, ss, sep="")
  }
  if(is.zero(x)){out <- "0"}
  cat(paste(strwrap(out, getOption("width")), collapse="\n"))
  
  cat("\n")
  return(invisible(x))
}

`vector_to_free` <- function(v,coeffs){
  if(missing(coeffs)){coeffs <- rep(1,length(v))}
  freealg(as.list(v),coeffs)
}

`string_to_freealg` <- function(string){
  if(nchar(string)==0){return(numeric_to_free(0))}
  string <- gsub("^\\+","",string)  # strip initial "+"
  string <- gsub("\\*","",string)   # strip all "*"
  minus <- length(grep("^-",string))>0
  if(minus){
    sign <- (-1)
    string <- gsub("^-","",string)
  } else {
    sign <- +1
  }

  if(length(grep("[0-9]",string))>0){
    coeff <- as.numeric(gsub("[a-z]|[A-Z]","",string))
    string <- gsub("[0-9]","",string)
  } else {
    coeff <- 1
  }
  out <- match(strsplit(string,"")[[1]], c(letters,LETTERS))
  if(any(out>26)){out[out>26] <- 26-out[out>26]}
  freealg(list(out),coeffs=sign*coeff)
}

`char_to_freealg` <- function(ch){ Reduce(`+`,lapply(ch,string_to_freealg))  }

`natural_char_to_freealg` <- function(string){
  string <- paste(string, collapse = " ")
  string <- gsub(" ","",string)  # strip spaces
  string <- gsub("\\+"," +",string) # 'A+B" -> "A +B"
  string <- gsub("\\-", " -",string) # "A-B" -> "A -B"
  char_to_freealg(strsplit(string," ")[[1]]) }

setGeneric("deriv")
`deriv.freealg` <- function(expr, r, ...){
    if(is.character(r)){
        rn <- numeric(length(r))
        if(length(r)==1){r <- strsplit(r,"")[[1]]}
        rn <- sapply(r,function(x){which(x==c(letters,LETTERS))}) # a=1,b=2...
        wanted <- rn>26
        rn[wanted] <- 26-rn[wanted]  # A=-1,B=-2,...
    } else {
        rn <- r
    }
    
    jj <- lowlevel_diffn(expr[[1]],expr[[2]],rn)
    return(freealg(jj[[1]],jj[[2]]))
}

`horner` <- function(P, v){
  P <- as.freealg(P)
  Reduce(v, right=TRUE, f=function(a,b){b*P + a})
}

`subsu` <- function(S1,S2,r){
    S1 <- as.freealg(S1)
    S2 <- as.freealg(S2)
    if(is.character(r) && (nchar(r)==1)){r <- which(letters==r)}
    out <- lowlevel_subs(S1[[1]],S1[[2]],S2[[1]],S2[[2]],as.integer(round(r[1])))
    freealg(out[[1]],out[[2]])
}

`subs` <- function(...) {
  sb <- list(...)[-1]
  v <- names(sb)
  out <- list(...)[[1]]
  for (i in seq_along(sb)) {
    out <- subsu(out, sb[[i]], v[i])
  }
  return(out)
}

`linear` <- function(x,power=1){
    a <- seq_along(x)
    jj <- cbind(a,power)
    freealg(sapply(a,function(i){rep(jj[i,1],jj[i,2])},simplify=FALSE),x)
}

`pepper` <- function(v){
    if(is.character(v)){
        v <- match(unlist(strsplit(v,"")),letters)
    }
    mv <- partitions::multiset(v)
    freealg(split(mv,col(mv)),rep(1,ncol(mv)))
}

`grade` <- function(x,n){
    if(missing(n)){stop("argument 'n' missing ... maybe you meant grades()?")}
    coeffs(x)[!(grades(x) %in% n)] <- 0
    return(x)
}

`grades` <- function(x){
  if(is.zero(x)){
    out <- -Inf
  } else {
    out <- disord(unlist(lapply(elements(words(x)),length)),hashcal(x))
  }
  return(out)
}

`grade<-` <- function(x, n, value){
    if(is.freealg(value)){
        stopifnot(all(grades(value) %in% n))
        grade(x,n) <- 0
        return(x+value)
    } else {
        coeffs(x)[grades(x) %in% n] <- value
        return(x)
    }
}

`deg` <- function(x){max(grades(x))}

`nterms` <- function(x){length(coeffs(x))}

`inv` <- function(S){
  if(nterms(S)==1){
    return(freealg(list(rev(-words(S)[[1]])),1/coeffs(S)))
  } else {
    stop("only freealg objects with exactly one term have a multiplicative inverse")
  }
}

`abelianize` <- function(x){
  freealg(lapply(elements(words(x)),function(x){x[order(abs(x))]}),elements(coeffs(x)))
}

setGeneric("drop")
setOldClass("freealg")
setMethod("drop","freealg", function(x){
    if(is.zero(x)){
        return(0)
    } else if(is.constant(x)){
        return(constant(x))
    } else {
        return(x)
    }
})

setGeneric("sort")
setGeneric("unlist")
setGeneric("lapply")

`all_pos` <- function(x){all(unlist(words(x))>0)}

`keep_pos` <- function(x){
  coeffs(x)[unlist(lapply(words(x),function(x){any(x<0)}))] <- 0
  return(x)
}

`[.freealg` <- function(x,...){
    wanted <- list(...)[[1]]
    coeffs(x)[!wanted] <- 0
    return(x)
}
         
`[<-.freealg` <- function(x,index,value){
    coeffs(x)[index] <- value
    return(x)
}
RobinHankin/freealg documentation built on Dec. 24, 2024, 3:16 a.m.