WeBWorK Problems

Sets of Numbers

Sets of Numbers

by Olivia Henders -
Number of replies: 9
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?
In reply to Olivia Henders

Re: Sets of Numbers

by Davide Cervone -
The MathObjects library has constructs for
  • Intervals of reals, including unbounded intervals, like [1,infinity),
  • Finite sets of reals, like {1,4,100}, and
  • Finite unions of the above.
Unfortunately, the set of integers is not one of the above, so there is no way to do that (currently) in MathObjects.

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.
In reply to Davide Cervone

Re: Sets of Numbers

by Olivia Henders -
Bummer...that's a shame that there isn't a straightforward way of implementing it. :-( Thank you for your help, though!
In reply to Davide Cervone

Re: Sets of Numbers

by Alex Jordan -
What if ".." or "..." was a new operator for capturing "all the integers from __ to __"? It could make a new kind of MathObject in the Set/Interval/Union family of MathObjects. "1...9" could have underlying data that was just the two numbers 1 and 9, thus helping with the printing issue mentioned in Davide's last post.

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".
In reply to Alex Jordan

Re: Sets of Numbers

by Michael Gage -
Just to make sure people are aware that 15..35 creates a list (array) of numbers from 15 to 35 in ordinary perl.

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/)

In reply to Michael Gage

Re: Sets of Numbers

by Davide Cervone -
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.
In reply to Alex Jordan

Re: Sets of Numbers

by Davide Cervone -
It is probably possible to add such a notation. While making a new MathObject class might be one way to go, I don't think that is necessary in this case, as you can probably use the existing classes, with some modifications.

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.
In reply to Davide Cervone

Re: Sets of Numbers

by Alex Jordan -
OK, but to clarify my intent, I'm suggesting doing nothing like what Perl does. 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).

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)").
In reply to Alex Jordan

Re: Sets of Numbers

by Davide Cervone -
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.)