Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error with brace and x #1050

Open
Alex-Jordan opened this issue Apr 7, 2024 · 9 comments
Open

error with brace and x #1050

Alex-Jordan opened this issue Apr 7, 2024 · 9 comments

Comments

@Alex-Jordan
Copy link
Contributor

In develop, with the following problem:

DOCUMENT();
loadMacros(qw(PGstandard.pl PGML.pl contextInequalitySetBuilder.pl));

Context("InequalitySetBuilder");
$sb = Formula("{x : x > 1}");

BEGIN_PGML
In set-builder notation: [_]{$sb}
END_PGML
ENDDOCUMENT();

If I type into a MQ answer blank {x:x>1} and submit the answer, syntax error at (eval 1515) line 6, near "$x :".

@drgrice1
Copy link
Sponsor Member

drgrice1 commented Apr 7, 2024

I do not believe that this has anything to do with MathQuill. It seems the same error occurs if MathQuill is not enabled for the course.

@Alex-Jordan
Copy link
Contributor Author

Oh, sorry. I was led to believe that matters, because we have these exercises with alternating MQ (for interval notation) and non-MQ (for set-builder notation) answer blanks, and it seemed like my testing only showed this in the non-MQ answer blanks. But maybe the context() of the answer matters for this.

@dpvc
Copy link
Member

dpvc commented Apr 7, 2024

I suspect the problem is due to using Formula() rather than Compute(), here. I'm not sure how to interpret a set-based formula, and how two could be compared. The error message is coming from the fact that x is interpreted as a variable in this formula, and so when the formula is converted to perl (for evaluation at several points), the x becomes $x. The default behavior for binary operators (which is how : is implemented) is to use the string version as the perl version (which makes sense for things like + and *, but not for :). it might be possible to fix this by setting a better value for the perl form for :, but I haven't tried to figure out what it should be.

But there is really no reason to use this as a Formula(), as it is not dependent on an external variable.

@Alex-Jordan
Copy link
Contributor Author

There is something else with this. If I:

  • log into a course and put this problem in the editor (still with Formula, not with Compute)
  • enter the offending answer {x:x>1} and click to Check Answers (generating the error)
  • click Check Answers again; and a third time
    Then I lose my session and have to log back in.

Actually it's the same if I change to Compute, getting green results with no errors. So this is a separate issue about session management. I have to run for the day or I'd report this more carefully.

@dpvc
Copy link
Member

dpvc commented Apr 7, 2024

Just a guess, but for Formula answers, there is a check about the previous answer being the same as the current one, so that would also produce the error about $x, and that might causing problems on second and subsequent answers.

@Alex-Jordan
Copy link
Contributor Author

@dpvc I would guess I'm in the top 1% of WW users as far as understanding MathObjects, but I still don't truly understand everything that goes on with Compute and Formula :) Anyway, I can change these exercises to use Compute, or to use whatever the explicit constructor is in this context. The question is then not about some issues I'm having with particular problem files, but rather is it reasonable for newbie PG coders to expect Formula to work here?

@dpvc
Copy link
Member

dpvc commented Apr 8, 2024

It turns out the perl() methods for the InequalitySetBuilder context are badly broken (they just inherit them from the Inequalities objects, which aren't what are needed here).

If you add

sub perl {
  my $self = shift;
  my $rop = $self->{coords}[0]{rop};
  return $self->Package('InequalitySetBuilder' . $rop->type)->new($rop)->perl;
}

to the InequalitySetBuilder::List::Set package, and

sub new {
  my $self = shift;
  $self = $self->Package($self->type)->new(@_);
  return $self->Package('SetBuilder')->new($self);
}

to the InequalitySetBuilder::common package, that should take care of the issue. Because a set is always a constant object, I guess I never considered needing the perl() methods, which are basically only needed for Formula comparisons. But these changes should take care of that.

Currently, the inequalities used in the sets must have the set variable on one side and a constant on the other. It would be potentially possible to allow a formula rather than a constant, so that set-values formulas would make sense. So you could do

Context()->variables->add(a => 'Real');

$S = Formula("{x : x > 2a+3}");

but that isn't currently allowed.

@dpvc
Copy link
Member

dpvc commented Apr 9, 2024

I would guess I'm in the top 1% of WW users as far as understanding MathObjects, but I still don't truly understand everything that goes on with Compute and Formula

Yes, I would say you are in the top 1% for this esoteric and finicky process. Kudos for being so successful with it!

As for Compute() and Formula(), the latter is the easier one (and the former relies on it). When you use Formula(), the result is always considered to be a function of the variables in the context, even when it is constant (in which case it is a constant-valued function). That means comparisons are always done via evaluating at the test points and comparing the results, even when constant (Formula should probably special-case that situation for efficiency).

Compute() is more complicated: it first calls Function() on its first argument, and if there are more arguments, it treats them as a hash of substitutions to perform on the formula, after first setting reduceConstants, reduceConstantFunctions, and showExtraParens to 0. Then if the formula is constant, the formula is evaluated (to get a Value object like Real or Complex rather than a function). Then Formula() is called on the original string again (this time with the reductions turned off to get the parsed version of the original formula as given by the author), and this is used to produce the string and TeX versions for the correct answer.

Finally, the reduction flags are returned to their original values, and the formula or constant Value object is returned. Some properties (like original_formula) are set along the way, but that is the main idea of what the two function do. I hope that helps.

@dpvc
Copy link
Member

dpvc commented Apr 10, 2024

I have looked further into the question of using set-valued formulas, and it turns out that the real culprit is the Inequalities contexts, which also don't properly implement the perl() method. It takes a bit of effort to get this to work, but I have created a patch that allows for inequalities (and set-builder sets) to use formulas on the other side of the inequality from the variable. I've attached a patch file that makes this possible. This allows for things like

$S1 = Compute("{ x : x > 3a + 1 }");
$S2 = Compute("{ x : a < x < 2a }");

and so on.

When x and a are both variables, however, it is not clear whether a < x should be treated as the values of a that are less than x or the values of x that are greater than a. Since this is interpreted using the definitions in contextInequalities.pl, we don't know what variable is going to be used to form the set, so that doesn't help use disambiguate expressions like a < x (or x < y).

To solve this, this patch allows you to mark a variable as an arbitrary "constant" using

Context()->variables->add(a => "Constant");

which is a real-valued variable that is to be considered a constant, but still takes part as a variable in formula comparisons. This is what allows the Inequalities contexts to determine which side of an inequality like a < x is the number and which the variable. So with

Context("Inequalities");
Context()->variables->add(a => "Constant");

$I = Compute("a < x");

the variable $I is an inequality equivalent to Compute("(a, inf)") as an interval. That is, it is a Formula object returning an interval as an inequality that has x as the variable and a as the number. The only variables that can be used on the number side of an inequality are ones that are marked as constants in this way.

In any case, this patch (against the current develop branch) will allow you to use Formula("{x : x > 1}") as in your original problem, and extends the use of inequalities and se-builder sets to situations where you want to use an arbitrary (unspecified) value in the inequalities, like {x : x > 2a }. I think I have covered all the bases in this patch, but I'm sure I haven't tested every possible situation, and there may still be some that need better handling. In particular, I haven't checked that all error situations produce meaningful messages. But it might be worth trying out.

This patch should not harm existing problems, as the formulas only come into play when there are variables set up as Constant variables, which was not available previously, or when Formula() is used explicitly, which would cause the error you had in the original post, so couldn't have been in a working problem to begin with. So I'm pretty sure this is a safe update, even though it is an extensive change to the inequality and set-builder contexts. (Famous last words.)

formula-inequalities.patch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants