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

Refine LimitedAccuracy's ⊑ semantics #48045

Merged
merged 2 commits into from
Jan 2, 2023
Merged

Refine LimitedAccuracy's ⊑ semantics #48045

merged 2 commits into from
Jan 2, 2023

Conversation

Keno
Copy link
Member

@Keno Keno commented Dec 30, 2022

As discussed in #48030, this is a different attempt to fix the semantics of LimitedAccuracy. This fixes the same test case as #48030, but keeps LimitedAccuracy ε smaller than its wrapped lattice element. The primary change here is that now all lattice elements that are strictly ⊑ T are now also ⊑ LimitedAccuracy(T), whereas before that was only true for other LimitedAccuracy elements.

Quoting the still relevant parts of #48030's commit message:

I was investigating some suboptimal inference in Diffractor
(which due to its recursive structure over the order of the
taken derivative likes to tickle recursion limiting) and
noticed that inference was performing some constant propagation,
but then discarding the result. Upon further investigation,
it turned out that inference had determined the function to be
`LimitedAccuracy(...)`, but constprop found out it actually
returned `Const`. Now, ordinarily, we don't constprop functions
that inference determined to be `LimitedAccuracy`, but this
function happened to have `@constprop :aggressive` annotated.

Of course, if constprop determines that the function actually
terminates, we do want to use that information. We could hardcode
this in abstract_call_gf_by_type, but it made me take a closer look
at the lattice operations for `LimitedAccuracy`, since in theory
`abstract_call_gf_by_type` should prefer a more precise result.

base/compiler/typelimits.jl Show resolved Hide resolved
issimplertype(lattice, typeb, typea) && return LimitedAccuracy(typeb, causesb)
elseif suba
issimplertype(lattice, typeb, typea) && return LimitedAccuracy(typeb, causesb)
causes = causesnb
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

causesb

causes = causesnb
# `a`'s causes may be discarded
elseif subb
causes = causesb
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symmetry?

Suggested change
causes = causesb
issimplertype(lattice, typea, typeb) && return LimitedAccuracy(typea, causesa)
causes = causesa

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issimplertype test is below, but yes this should have been causesa.

@@ -368,7 +404,8 @@ ignorelimited(typ::LimitedAccuracy) = typ.typ
function ⊑(lattice::InferenceLattice, @nospecialize(a), @nospecialize(b))
if isa(b, LimitedAccuracy)
if !isa(a, LimitedAccuracy)
return false
# epsilon smaller
return ⊑(widenlattice(lattice), a, b.typ) && !⊑(widenlattice(lattice), b.typ, a)
end
if b.causes ⊈ a.causes
return false
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should reflect the epsilon case too, though I think that means refactoring part of this code for better ordering than this

Suggested change
return false
if (widenlattice(lattice), a.typ, b.typ)
return true
end
return false

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This also must be reflected now in the type-complexity tests. Where this is meaning the comparison of the length of causes.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the type-complexity tests

You mean issimplertype? In the current design, that's not reached for LimitedAccuracy and before we were just passing those arguments through ignorelimited.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. It seems a little odd for tmerge_fast_path not to be legal anymore for this type, but I guess that looks right. We should perhaps assert there since we know LimitedAccuracy may be handled wrong there now?

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were correct before, since it was already implied by the precondition of suba or subb. That assumed implication is no longer valid after this change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me remove the ignorelimited in issimplertype then. We'll get an appropriate assertion if somebody accidentally uses it.

@Keno
Copy link
Member Author

Keno commented Dec 30, 2022

@nanosoldier runtests()

@nanosoldier
Copy link
Collaborator

Your package evaluation job has completed - possible new issues were detected. A full report can be found here.

As discussed in #48030, this is a different attempt to fix
the semantics of LimitedAccuracy. This fixes the same test
case as #48030, but keeps `LimitedAccuracy` ε smaller than
its wrapped lattice element. The primary change here is
that now all lattice elements that are strictly `⊑ T` are
now also `⊑ LimitedAccuracy(T)`, whereas before that was only
true for other `LimitedAccuracy` elements.

Quoting the still relevant parts of #48030's commit message:

```
I was investigating some suboptimal inference in Diffractor
(which due to its recursive structure over the order of the
taken derivative likes to tickle recursion limiting) and
noticed that inference was performing some constant propagation,
but then discarding the result. Upon further investigation,
it turned out that inference had determined the function to be
`LimitedAccuracy(...)`, but constprop found out it actually
returned `Const`. Now, ordinarily, we don't constprop functions
that inference determined to be `LimitedAccuracy`, but this
function happened to have `@constprop :aggressive` annotated.

Of course, if constprop determines that the function actually
terminates, we do want to use that information. We could hardcode
this in abstract_call_gf_by_type, but it made me take a closer look
at the lattice operations for `LimitedAccuracy`, since in theory
`abstract_call_gf_by_type` should prefer a more precise result.
```
Keno added a commit to JuliaDiff/Diffractor.jl that referenced this pull request Dec 31, 2022
Tests currently depend on JuliaLang/julia#48045
and JuliaLang/julia#48059, so we should either
get those merged first, or mark them here as broken.
base/compiler/abstractinterpretation.jl Outdated Show resolved Hide resolved
base/compiler/typelattice.jl Outdated Show resolved Hide resolved
base/compiler/typelimits.jl Outdated Show resolved Hide resolved
Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>
@Keno
Copy link
Member Author

Keno commented Jan 2, 2023

I think this should be good to go. PkgEval looks good.

@Keno Keno merged commit fe45f01 into master Jan 2, 2023
@Keno Keno deleted the kf/limaccpos2 branch January 2, 2023 18:56

# a and b's unlimited types are equal.
isa(a, LimitedAccuracy) || return false # b is limited, so ε smaller
return a.causes ⊆ b.causes
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code used to have the inverse check here

Suggested change
return a.causes b.causes
return b.causes a.causes

Was this supposed to get switched here? I think that is incorrect now, as the wider result should have fewer causes, but this does the opposite.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me double check. I don't think I intended to switch it - it's possible I got my cases mixed up.

# Approximated types are lattice equal. Merge causes.
if suba && subb
causes = merge_causes(causesa, causesb)
issimplertype(lattice, typeb, typea) && return LimitedAccuracy(typeb, causesb)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
issimplertype(lattice, typeb, typea) && return LimitedAccuracy(typeb, causesb)
issimplertype(lattice, typeb, typea) && return LimitedAccuracy(typeb, causes)

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think symmetry and equality demands that you are not supposed to check issimplertype in this case (see tmerge_fast_path)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we are still changing the lattice element here potentially if the causes are different, but yes fair enough, I'll drop the issimplertype check.

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point though. Is this new tmerge algorithm monotonic and convergent? In particular, this merge call here (with the heuristic towards shorter lengths but calling union if undecidable) seems like it might make inference non-terminating as it repeatedly merged and dropped causes lists here in a loop

Keno added a commit that referenced this pull request Jan 4, 2023
As discussed in #48045:
1. Switch the order of `causes` inclusion to make wider
   elements have fewer causes.
2. Fix two typos
3. Restore property that equal ulimited types will be
   preserved (though with potentially updated `causes` lists).
Keno added a commit to JuliaDiff/Diffractor.jl that referenced this pull request Jan 5, 2023
* Hookup demand-driven forward mode to the Diffractor runtime

Tests currently depend on JuliaLang/julia#48045
and JuliaLang/julia#48059, so we should either
get those merged first, or mark them here as broken.

* Mark test as broken
vtjnash pushed a commit that referenced this pull request Jan 22, 2023
As discussed in #48045:
1. Switch the order of `causes` inclusion to make wider
   elements have fewer causes.
2. Fix two typos
3. Restore property that equal ulimited types will be
   preserved (though with potentially updated `causes` lists).
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

Successfully merging this pull request may close these issues.

None yet

4 participants