Is there a way to allow students to reference sets of numbers aside from the reals?

E.g. The interval (-Inf, 1) U (1, Inf) could also be specified by R - {1}. However, what if you were only dealing with integers and wanted to have Z - {1} as the answer?

The set of reals seems to exist by default, but can others be added to the context?

- Intervals of reals, including unbounded intervals, like
`[1,infinity)`

, - Finite sets of reals, like
`{1,4,100}`

, and - Finite unions of the above.

My initial thought was to suggest that you use a set like

Context()->constants->add(Z => Set(-1000..1000));as a surrogate for

**Z**, and this works as far as computations and checking go, but it has one important problem: it would print itself by displaying all 2001 entries in the set. Furthermore, while we can certainly compute things like

`Z - {0}`

using a set like this, there is not compact notation (available in MathObjects) for printing the result. Note that `R - {0}`

prints as `(-infinity,0) U (0,infinity)`

, so there is a compact notation for that.
So this use case is not covered by the MathObjects library without adding new MathObject classes. Of course that could be done, but it is highly non-trivial to do it. I could imagine using a notation like `{..., -3, -2, -1, 1, 2, 3, ...}`

for `Z - {0}`

, but I'd have to think hard about what the proper internal data format would need to be in order to handle these situations efficiently, while still interacting with the current sets, intervals, and unions.

In terms of adding other named sets to the context, yes, you can do that (I illustrated one case above. For example, you could do

Context()->constants->add(I => Compute("[0,1]"));to add

`I`

as the (closed) unit interval.
It could allow for things like "1...inf". It could have "-inf...inf" and "-inf...inf - {0}", the latter of which is equivalent to "-inf...-1 U 1...inf".

Davide says adding a new MathObject class is highly nontrivial. Is what I am proposing here "adding a new MathObject class"? It probably is. The ways that it could interact with other set/interval/union objects would all have to be figured out.

I came back to this because someone in the PreTeXt forum basically just asked about having a WeBWorK quesiton where the answer would be "15...35".

That doesn't solve the printing problem if you want it displayed as 15..35 nor does it allow for infinities. It does allow you or a student to enter a consecutive string of numbers easily.

Adding a filter to the existing Set class to display consecutive strings of integers using ... notation would probably be easier than creating a new class.

--------------------

I got curious about the three vs. two dots question so I looked it up

(https://perlhacks.com/2014/01/dots-perl/)

*It does allow you or a student to enter a consecutive string of numbers easily*Only the problem author has access to Perl's

`..`

operator (two dots, not three), not the student. To give student that ability, you would need to add an operator to the Context that implements that feature.
Good point.

I have some concerns about the notation, however. In Perl

`1..5`

is equivalent to the list `(1,2,3,4,5)`

; since MathObjects has both list and set objects, I would expect `1..5`

to produce a List object, e.g., `List(1,2,3,4,5)`

, and `{1..5}`

to produce a set, e.g. `Set(1,2,3,4,5)`

.For

`a..b`

where `a`

and `b`

are both finite, this would be relatively easy to do, and does not require any changes to the MathObject classes, only a new operator in the Context. Changes to the output for Lists and Sets to reduce `1, 2, 3, 4, 5`

back to `1..5`

would be useful for keeping the output small.To handle something like

`1..inf`

would require substantial changes, however, since both the List and Set objects are for *finite*lists and sets only. One possibility would be to use the Interval class instead (which does handle infinite intervals), and add a flag that indicates an integer-only interval (or some such thing). The main work would be in the computational routines that handle set unions, intersections, differences, and so on, so that they handle integer intervals properly, and generate the proper results. Those routines are pretty complicated already, so this is non-trivial, but it would certainly be possible, with some effort.

Getting everything right, and producing the proper messages in all cases would take some careful work. I'm sorry these things aren't easier to do.

I'm thinking similar to how the half-open interval [1,5) is really the Perl array (1, 5) with the interval type stored separately in open- and close- delimiters that are separately stored.

If the context is Interval, Compute("[1, 5)")->{data} is something like [1,5,'[',')'], although I may not have certain details right there. I'm tossing out that Compute("1..5")->{data} could be [1,5,'..'] or whatever would make more sense. And then Compute("1..inf")->{data} could just be [1,inf,'..'] and not substantially different in nature.

I understand and agree with what you say about braces. Just omitting them for now.

Maybe it would raise difficulties to check equality between things like Compute("{1..3}") and Compute("[1,3] - (1,2) - (2,3)") and Compute("{1..inf} - [4,inf)").

*I would not want*`1..5`

to become `1,2,3,4,5`

. I would want it to become something whose underlying data is still just the Perl array `(1,5)`

.My suggestion of adding an "integer only" flag to the current interval object would operate in the manner you suggest. My suggestion that

`1..5`

becomes `1, 2, 3, 4,5`

was meant as a way to get a (substantial) subset of the functionality now without significant adjustment to the underlying classes. It is not ideal, certainly (as you could produce large sets too easily, for example).I would expect

`{1, 2, 3, 4, 5}`

to match `{1..5}`

, wouldn't you (that is, one answer would be accepted for the other)? So an implementation that did make `1..5`

become `1, 2, 3, 4, 5`

would make that trivial. But I understand the desire for a more compact internal format, and that's why the current Interval object could be one solution.Yes, your computation examples are the kinds of things that make it complicated to get all the details right. These are the same kinds of details that have to be taken into account for

`{1,3}`

compared to `[1,3] - (1,3)`

in the current set of objects. You would also need to deal with things like `{1..5}`

compared to `{1..3} U {2..5}`

and `{1..10} - {6..12}`

and other such possibilities. The key, it seems to me, is guaranteeing the equivalence of `{1..5}`

and `{1, 2, 3, 4, 5}`

in terms of the computations. From a student's point of view, I don't think these should be different things. The internal representation is immaterial from their standpoint. For the problem author, one should be able to move between the two formats as desired. For example, if you make

`IntegerInterval()`

as a way to produce integer intervals, then `IntegerInterval(Set(1,2,3,4,5))`

would produce the object that is `{1..5}`

, while `Set(IntegerInterval(1,5))`

would produce the set `{1, 2, 3, 4, 5}`

. (Of course, both could produce errors if the conversion can't be made, e.g., `IntegerInterval(Set(1,3,5))`

or `Set(IntegerInterval(1,Infinity))`

, or they could return the original objects again.)