2

(I'm using the word "field" in the mathematical sense; base fields/corpora which R already uses include the real and complex numbers.)

I'm interested in allowing some other base fields/corpora (like F₅, which is modular arithmetic in base 5). To do that I would need to

  1. define a new data type
  2. overload the relevant operators (+, *, and maybe more)
  3. maybe something else? e.g., integrate with other functionality?

So, how does one define a new data type or overload operators in R?

IRTFM
  • 258,963
  • 21
  • 364
  • 487
isomorphismes
  • 8,233
  • 9
  • 59
  • 70
  • 1
    You probably want to start with defining a class. So pick S3 or S4, then define class. Overloading is pretty simple where permitted (in most places). What is the ultimate goal for this? Check out ggplot's overloading of the `+` operator for one example. – Ari B. Friedman Nov 05 '11 at 22:59
  • @gsk3 Do you have a link to some documentation? I don't know how to decide whether `S3` or `S4` is better for this purpose. The goal is to be able to do matrix operations over different fields and thus model sporadic groups. It could be done in other languages but I'm trying to get better with `R`. – isomorphismes Nov 06 '11 at 00:20

2 Answers2

10

I found Hadley Wickham's devtools wiki an invaluable resource for getting started with classes in R. In particular, read the sections on:

Here is a starting point that illustrates some of the concepts in S3 classes. Let's call your new class f5. At a minimum, you would probably want to create methods for:

  • Coercion: as.f5
  • Test: is.f5
  • Some basic operators: +.f5
  • A class to handle printing: print.f5

Some code (using digitsBase in package GLDEX to do the base conversion):

library(GLDEX)

as.f5 <- function(x){
  if(!inherits(x, "f5")) class(x) <- c("f5", class(x))
  x
}

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

`+.f5` <- function(e1, e2){
  NextMethod(e1, e2)
}

print.f5 <- function(x, ...){
  # Next line from ?GLDEX::digitsBase
  b2ch <- function(db) noquote(gsub("^0+(.{1,})$"," \1", 
                           apply(db, 2, paste, collapse = "")))

  cat("Base 5:\n")
  cat(b2ch(digitsBase(x, 5)))
  invisible(x)
}


x <- as.f5(0:10)
y <- as.f5(5)

x + y

Base 5:
10 11 12 13 14 20 21 22 23 24 30
Andrie
  • 176,377
  • 47
  • 447
  • 496
4

I interpreted your question a bit differently than @Andrie, but he has already done a bunch of the needed S3 class work. I thought you wanted to develop group operations on a group with five elements, or perhaps a ring. You would then want a "+" operation with an identity element == 0 and perhaps a "*" operation with an identity element == 1.

If you wanted the nonnegative integers mapped into this, you would use the modulo arithmetic operators, %% and perhaps %/%:

?Ops
as.g5 <- function(x){
  if(!inherits(x, "g5")) class(x) <- c("g5", class(x))
  x %% 5
}

print.g5 <- function(x, ...){

  cat("G5 equivalent:\n")
  cat(x %% 5)
  invisible(x)
}

If you wanted two operators you might be looking for:

 `+.g5` <- function(e1, e2){
   NextMethod(e1 ,e2) %% 5
 }

 `*.g5` <- function(e1, e2){
   NextMethod(e1 ,e2) %% 5
 }
 x <- as.g5(0:10)
 y <- as.g5(5)

 x + y
#G5 equivalent:
#0 1 2 3 4 0 1 2 3 4 0
 y <- as.g5(2)
 x * y
#G5 equivalent:
#0 2 4 1 3 0 2 4 1 3 0

It's also possible to use these operation on "volatile" versions of vectors:

 as.g5(1:10) * as.g5(1:10)
# G5 equivalent:
# 1 4 4 1 0 1 4 4 1 0
isomorphismes
  • 8,233
  • 9
  • 59
  • 70
IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Thank you. You interpreted my question correctly; that is what I want to do. How is your answer different than @Andrie's? – isomorphismes Nov 08 '11 at 04:44
  • 2
    He illustrated how to implement a base 5 number system that spans a theoretically unbounded (but practically limited by machine and software constraints) range with an addition operation. I offered a 5 element finite group with two operations. (If my memory holds I constructed a ring as well.) – IRTFM Nov 08 '11 at 04:49
  • Yes: a field is a commutative ring with multiplicative inverses, so all fields are rings but the reverse does not hold. Thanks for the clarification. Is your way more memory efficient since it's "smaller"? – isomorphismes Nov 08 '11 at 08:45
  • I do note that each G5 with ordinary modulo multiplication has a multiplicative inverse, so I think I met all the requirements , except perhaps adding a `g5/` operation, but your path to success would seem clear. – IRTFM Nov 08 '11 at 14:24
  • And I don't think it makes sense to ask the relative efficiency of two methods, when they don't deliver the same result. A finite group is not the same mathematical object as implementing integers with a base-5 print method. – IRTFM Jan 15 '16 at 00:46