-
Notifications
You must be signed in to change notification settings - Fork 112
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
Cache computed properties for toric varieties #839
Conversation
There is already a mechanism for this using Oscar.jl/src/Rings/FinField.jl Lines 26 to 33 in 79d65df
For this the structure needs just one additonal declaration, e.g. Lines 137 to 140 in d34d698
@fieker rolled this out, so maybe he has an idea on whether we should try to use this everywhere in Oscar. |
On Mon, Nov 29, 2021 at 02:01:40AM -0800, Tommy Hofmann wrote:
There is already a mechanism for this using ***@***.***_other` and `set_special/get_special`, see for example https://github.com/oscar-system/Oscar.jl/blob/79d65df00327fb6009e9c137bbf2bd83e39475b0/src/Rings/FinField.jl#L26-L33
For this the structure needs just one additonal declaration, e.g.
https://github.com/oscar-system/Oscar.jl/blob/d34d698db39583b5fd24ca4e3e375a17684fbdd9/src/Groups/types.jl#L137-L140
@fieker rolled this out, so maybe he has an idea on whether we should try to use this everywhere in Oscar.
I thnk it should be used uniformely everywhere - that allows us to
improve it also uniformely everywhere (e.g. rename it...)
… --
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#839 (comment)
|
Yeah, we ought to (a) rename |
src/ToricVarieties/CyclicQuotientSingularities/CyclicQuotientSingularities.jl
Outdated
Show resolved
Hide resolved
test/ToricVarieties/runtests.jl
Outdated
@@ -74,7 +74,9 @@ P2 = toric_projective_space(2) | |||
@test length(irrelevant_ideal(P2).gens) == 3 | |||
end | |||
|
|||
H5 = hirzebruch_surface(5) | |||
rays = [1 0; 0 1; -1 5; 0 -1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ERROR: LoadError: cannot assign a value to variable Oscar.rays from module Main
(*) affine toric varieties (*) normal toric varieties (*) cyclic quotient singuarlties
77da1a9
to
4c28072
Compare
|
||
# if no Betti numbers have been computed | ||
betti_numbers = Vector{fmpz} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
betti_numbers = Vector{fmpz} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line was intended for type stability, as I wanted to save these numbers always as fmpz (rather than Int, Int64). If removed, I might have to change the following line 19 to betti_numbers = fill(fmpz(-1),2*dim(v)+1)
, i.e. explicitly invoking the cast of -1
to fmpz(-1)
there. (Which is of course ok.)
A related question. As there are several Betti numbers for one variety, it seems reasonable to cache them in a vector. Currently, I fill this vector with -1
at each position. As Betti numbers are always non-negative, a -1
tells that the corresponding Betti number has not (yet) been computed.
But maybe there is a better way than filling with -1
s. E.g. to create a vector of suitable length by no entries set and then perform a check if an entry has been set? Suggestions very much appreciated.
This question/issue/challenge repeats for line bundle cohomologies (which I hope to turn to very soon).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line does not do anything useful: in particular that value is immediately discarded in the following two lines. If you want type stability for this variable, you need to adjust each assignment to it to ensure the right type is assigned, eg via a type assertion and/or an explicit conversion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. Adjusted in 0113ddb.
if !has_attribute(cqs, :continued_fraction_hirzebruch_jung) | ||
set_attribute!(cqs, :continued_fraction_hirzebruch_jung, Vector{fmpz}(pm_object(cqs).CONTINUED_FRACTION)) | ||
end | ||
return get_attribute(cqs, :continued_fraction_hirzebruch_jung) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and several similar functions could be simplified by using
return get_attribute!(cqs, :continued_fraction_hirzebruch_jung) do
return Vector{fmpz}(pm_object(cqs).CONTINUED_FRACTION)
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I am thinking about a system to make this stuff even nicer, inspired by GAP but my brain is still mushy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. That is a good suggestion. Indeed, this change can be done in a ton of places. I will do this in a new commit rather than rebasing everything (unless I hear differently).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjusted in d9efae2
end | ||
end | ||
|
||
# torusfactor? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?? Doesn't seem to fit the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - I will update this comment (which was intended to say "check what we know about the torusfactor").
NVM: This comment is entirely out of place (copied from the corresponding output string from toric varieties)...
I will adjust this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjusted in 36f51bf.
|
||
# torusfactor? | ||
if last(out_string) == ',' | ||
out_string = chop(out_string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I'd write this kind of function differently: first create a Vector{String} and push! all those adjectives into it. Then use join
to concatenate cleverly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I will adjust accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function Base.show(io::IO, td::ToricDivisor) | ||
print(io, "A torus invariant divisor on a normal toric variety") | ||
print(io, output_string(td)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this way? Why not instead print into a string when you really need one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thoughts were no deeper than extending the existing code. As always, I am happy to change to a more robust/preferred/quicker alternative. Are saying that print(output_string(td))
is better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I am saying that instead of shoving data into a string and then printing it, it is better to directly print it. And if you sometimes really want a string, you can simply print into a string.
Notw that even join
takes an io argument and can thus print instead of creating a (temporary) string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change name of method: ith_betti_number -> betti_number
return get_attribute!(v, :dim) do | ||
return pm_object(v).FAN_DIM::Int | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think some care is needed to retain type stability; the type assertion needs to be moved to the outer return. I think this might work (but didn't test):
return get_attribute!(v, :dim) do | |
return pm_object(v).FAN_DIM::Int | |
end | |
return get_attribute!(v, :dim)::Int do | |
return pm_object(v).FAN_DIM | |
end |
You can verify if it worked by (a) calling it (to makes sure I got the syntax right, I am not sure), and (b) using @code_warntype
on it to verify the return type is inferred correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the suggestion @fingolfin . For me, this change leads to the following:
ERROR: LoadError: LoadError: LoadError: syntax: "function" at Oscar.jl/src/ToricVarieties/NormalToricVarieties/attributes.jl:11 expected "end", got "do"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all it matters, here is a MWE via @code_warntype
, which supports your suspicion that type stability requires more care:
v = toric_projective_space(2)
A normal, non-affine, smooth, projective, gorenstein, q-gorenstein, fano, 2-dimensional toric variety without torusfactor
julia> @code_warntype dim(v)
Variables
#self#::Core.Const(AbstractAlgebra.Generic.dim)
v::NormalToricVariety
#1418::Oscar.var"#1418#1419"{NormalToricVariety}
Body::Any
1 ─ %1 = Oscar.:(var"#1418#1419")::Core.Const(Oscar.var"#1418#1419")
│ %2 = Core.typeof(v)::Core.Const(NormalToricVariety)
│ %3 = Core.apply_type(%1, %2)::Core.Const(Oscar.var"#1418#1419"{NormalToricVariety})
│ (#1418 = %new(%3, v))
│ %5 = #1418::Oscar.var"#1418#1419"{NormalToricVariety}
│ %6 = Oscar.get_attribute!(%5, v, :dim)::Any
└── return %6
Hence, if I read this information correctly, Body::Any
show that the return type is Any
rather than Int
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about turning function dim(v::AbstractNormalToricVariety)
into dim(v::AbstractNormalToricVariety)::Int
? This would seem to work and - based on @code_warntype - enusure that the return value is always Int64
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am uncertain if the failures in the runs of the nightly build (ERROR: LoadError: Failed to precompile CxxWrap) are correlated to the changes in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
writing dim(v::...)::Int
has different meaning, though: it converts the result to Int
, by inserting a call to convert(Int, ...)
; while a type assertion does just that, it checks that the value is an Int
(if not, an exception is thrown).
Anyway, let's not worry about this for the moment. I describe a potential future solution for this in another comment.
e9e947a
to
4fd4a6e
Compare
Rename "rays" to "fan_rays"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
From my POV we could merge now; the things I mention are truly minor. I'll do it tomorrow or the day after if I hear no complaints
function euler_characteristic(v::AbstractNormalToricVariety) | ||
f_vector = Vector{Int}(pm_object(v).F_VECTOR) | ||
return f_vector[dim(v)] | ||
return get_attribute!(v, :euler_characteristic) do | ||
f_vector = Vector{Int}(pm_object(v).F_VECTOR) | ||
return f_vector[dim(v)] | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clearly this is a recurring pattern, and one that I'd expect to see more in the future. It would be good to get this closer to what e.g. GAP (and probably also Polymake and other systems) can do in terms of ease of use and capabilities. E.g. having a general way to test if a value is already known. In GAP parlance, for every attribute Attr
there is a "tests" HasAttr
to detect if the attribute value is known. We could do the same and have methods like has_euler_characteristic
(or haseuler_characteristic
but I like it more with the underscore?); or perhaps it should be knows_euler_characteristic
?
Anyway, a potential macro syntax
@attribute function euler_characteristic(v::AbstractNormalToricVariety)
f_vector = Vector{Int}(pm_object(v).F_VECTOR)
return f_vector[dim(v)]
end
So really the old code just with @attribute
prefixed. Also available for inline functions, and it should be engineered to also transfer information about the return type, whether from type assertions or by regular type inference (by using Base.return_types
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that would be great.
return get_attribute!(v, :dim) do | ||
return pm_object(v).FAN_DIM::Int | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
writing dim(v::...)::Int
has different meaning, though: it converts the result to Int
, by inserting a call to convert(Int, ...)
; while a type assertion does just that, it checks that the value is an Int
(if not, an exception is thrown).
Anyway, let's not worry about this for the moment. I describe a potential future solution for this in another comment.
Return the toric variety of a torus-invariant Weil divisor. | ||
""" | ||
function toricvariety(td::ToricDivisor) | ||
return get_attribute(td, :toricvariety) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will return nothing
if toricvariety
is not set. Is this intentional? Or can it never happen? But if it can never happen, then why is toricvariety
even an attribute instead of a regular struct field?
If it really should stay an attribute, at least add a type assertion?
return get_attribute(td, :toricvariety) | |
return get_attribute(td, :toricvariety)::AbstractNormalToricVariety |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right - let me turn this into a struct field (it will be set upon construction of every toric divisor td
).
Thank you @fingolfin. |
Co-authored-by: Max Horn <max@quendi.de>
properties
andattributes
to structNormalToricVarieties
,AffineNormalToricVarieties
,ToricDivisors
.Please note that this PR contains the changes of #838. In this sense it is a draft and must be rebased once this other PR has been merged.