Opened 2 years ago
Closed 2 years ago
#27993 closed defect (fixed)
Make outer normal fans readily available
Reported by:  nailuj  Owned by:  

Priority:  major  Milestone:  sage8.9 
Component:  geometry  Keywords:  NormalFan, polytope, days100 
Cc:  jipilab  Merged in:  
Authors:  Julian Ritter  Reviewers:  JeanPhilippe Labbé, Frédéric Chapoton 
Report Upstream:  N/A  Work issues:  
Branch:  440689c (Commits, GitHub, GitLab)  Commit:  440689c758f36b80c4dd0a9a88eee5c5d60f2b22 
Dependencies:  Stopgaps: 
Description (last modified by )
For a polytope P
, both NormalFan(P)
and P.normal_fan()
return the inner normal fan having the inner facet normals as rays. The outer normal fan, using the outer facet normals, is wellknown, but not as easy to find in Sage.
As an example, create the polytope on p.193 of Ziegler's "Lectures on Polytopes" with its normal fan:
sage: V=[(8,4),(8,6),(4,8),(0,9),(0,6),(4,8)] sage: P=Polyhedron(V) sage: NormalFan(P)
The result is the inner normal fan of P
, which is the outer normal fan of P
.
This ticket adds to Polyhedron.normal_fan
an argument direction
set to either 'inner'
or 'outer'
to determine which of the directions to use. The default will stay 'inner'
in order to match the default of NormalFan
. The description of NormalFan
is extended by a hint to use NormalFan(P)
for the outer normal fan.
Additionally, this ticket adds in sage.geometry.polyhedron.representation
a method Inequality.outer_normal
.
This allows to obtain the outer normal vector without having to think about the appropriate sign of Inequality.A()
whenever dealing with the facet inequalities of a polyhedron.
Change History (22)
comment:1 Changed 2 years ago by
 Branch set to u/nailuj/normalfan_outer
comment:2 Changed 2 years ago by
 Commit set to 484bf563c383e0b0fc85fd3e2af991dfb41a9932
 Status changed from new to needs_info
comment:3 Changed 2 years ago by
 Milestone changed from sage8.8 to sage8.9
Sage 8.8 is to be released fairly soon so unless this is a blocker this should be moved to the next release.
comment:4 followup: ↓ 5 Changed 2 years ago by
I don't care much about adding direction
argument, but I have extremely strong objection to making it the default. There was a reason why inner normals were used for many, many years (like since 2006)  it is consistent with the literature. I understand that some books/articles use the other way, but when neither way is exceptionally uncommon the default choice is pretty much random personal preference when you first create these classes and methods. Once they were created and used for a long time, there is absolutely no reason to change the default whatever it is.
comment:5 in reply to: ↑ 4 Changed 2 years ago by
Replying to novoselt:
I don't care much about adding
direction
argument, but I have extremely strong objection to making it the default. There was a reason why inner normals were used for many, many years (like since 2006)  it is consistent with the literature. I understand that some books/articles use the other way, but when neither way is exceptionally uncommon the default choice is pretty much random personal preference when you first create these classes and methods. Once they were created and used for a long time, there is absolutely no reason to change the default whatever it is.
+1
I would leave the default as it is and add the direction
argument to allow to get the variant.
comment:6 followup: ↓ 7 Changed 2 years ago by
Actually, I think now it would be better to allow quick "direction flip" either on the polytope or the fan, i.e. make them support 
operator, instead of making constructors more complicated.
comment:7 in reply to: ↑ 6 Changed 2 years ago by
Replying to novoselt:
Actually, I think now it would be better to allow quick "direction flip" either on the polytope or the fan, i.e. make them support

operator, instead of making constructors more complicated.
This seems to already be possible for Polyhedron
objects:
sage: p = polytopes.regular_polygon(5) sage: p.vertices() (A vertex at (0.5877852522924731?, 0.8090169943749474?), A vertex at (0.9510565162951536?, 0.3090169943749474?), A vertex at (0, 1), A vertex at (0.5877852522924731?, 0.8090169943749474?), A vertex at (0.9510565162951536?, 0.3090169943749474?)) sage: (p).vertices() (A vertex at (0.5877852522924731?, 0.8090169943749474?), A vertex at (0.9510565162951536?, 0.3090169943749474?), A vertex at (0, 1), A vertex at (0.587785252292474?, 0.8090169943749474?), A vertex at (0.9510565162951536?, 0.3090169943749474?))
Or you have something else in mind?
Yes, I would use NormalFan(P)
or NormalFan(P)
depending on whether one wants the inner or outer. This seems like the easiest thing to do. One does not need to go into the Polyhedron
constructor...
comment:8 followup: ↓ 9 Changed 2 years ago by
That's exactly what I meant. I think those who care about directions are likely to read the documentation and discover that these are inner normals. After that, if this is not the desired choice for the user, NormalFan(P)
seems easier and cleaner to use than NormalFan(P, direction="outer")
.
comment:9 in reply to: ↑ 8 Changed 2 years ago by
 Status changed from needs_info to needs_work
Replying to novoselt:
That's exactly what I meant. I think those who care about directions are likely to read the documentation and discover that these are inner normals. After that, if this is not the desired choice for the user,
NormalFan(P)
seems easier and cleaner to use thanNormalFan(P, direction="outer")
.
I believe that the proposed change would be in the method .normal_fan()
of Polyhedron
objects, and not at the level of NormalFan
, for the reason you mention.
That said, I would change the description of the ticket as follows:
I propose to add to
normal_fan
an argument direction set to either'outer'
or'inner'
to determine which of the directions to use. The default will stay inner in order to match the default ofNormalFan
.
Above I would keep the current default.
Additionally, I propose to add in sage.geometry.polyhedron.representation a method Inequality.outer_normal. This allows to obtain the outer normal vector without having to think about the appropriate sign of Inequality.A() whenever dealing with the facet inequalities of a polyhedron.
This is good to me.
Further, I would suggest to add
Use
NormalFan(P)
to get the outer normal fan.
in the documentation of NormalFan
.
comment:10 Changed 2 years ago by
 Commit changed from 484bf563c383e0b0fc85fd3e2af991dfb41a9932 to b41def5d69156640996e4a6e60d29d17b36bd435
comment:11 Changed 2 years ago by
 Commit changed from b41def5d69156640996e4a6e60d29d17b36bd435 to fd3e89926e9648fb36bb2c087deb24b0c3938ef1
Branch pushed to git repo; I updated commit sha1. New commits:
fd3e899  Fixed typo

comment:12 Changed 2 years ago by
 Description modified (diff)
 Status changed from needs_work to needs_review
Replying to jipilab:
Replying to novoselt:
That's exactly what I meant. I think those who care about directions are likely to read the documentation and discover that these are inner normals. After that, if this is not the desired choice for the user,
NormalFan(P)
seems easier and cleaner to use thanNormalFan(P, direction="outer")
.I believe that the proposed change would be in the method
.normal_fan()
ofPolyhedron
objects, and not at the level ofNormalFan
, for the reason you mention.
Yes. I stumbled upon this innerouter issue through Polyhedron.normal_fan()
. This is why I added jipilab in CC in the first place, and this is where I should have proposed to make 'outer'
the default – my bad. I'm fine with 'inner'
as default in both files. My main goal was easier access to outer normal fans, which is now available and explained in the docstrings.
That said, I would change the description of the ticket as follows:
I propose to add to
normal_fan
an argument direction set to either'outer'
or'inner'
to determine which of the directions to use. The default will stay inner in order to match the default ofNormalFan
.
Done.
Further, I would suggest to add
Use
NormalFan(P)
to get the outer normal fan.in the documentation of
NormalFan
.
Done.
comment:13 followup: ↓ 15 Changed 2 years ago by
 Keywords days100 added
 Reviewers set to JeanPhilippe Labbé
 Status changed from needs_review to needs_work
 The optional parameters should receive an appropriate doctest. For example:
sage: p = polytopes.regular_polygon(4,base_ring=QQ).pyramid() sage: inner_nf = p.normal_fan() sage: inner_nf.rays() N( 1, 0, 0), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1) in 3d lattice N sage: outer_nf = p.normal_fan(direction='outer') sage: outer_nf.rays() N(1, 0, 0), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1) in 3d lattice N
 Further, it would be nice to disallow such things:
sage: outer_nf = p.normal_fan(direction='blabla')
by checking that direction is one of the two allowed things (see the volume function for a similar handling).
 Remove the space before the semicolon in the docstring of
normal_fan
.
comment:14 Changed 2 years ago by
 Commit changed from fd3e89926e9648fb36bb2c087deb24b0c3938ef1 to 308dada78b84d1436dca28bd970e768d6ea6c42b
comment:15 in reply to: ↑ 13 Changed 2 years ago by
 Status changed from needs_work to needs_review
Replying to jipilab:
The optional parameters should receive an appropriate doctest. For example:
sage: p = polytopes.regular_polygon(4,base_ring=QQ).pyramid() sage: inner_nf = p.normal_fan() sage: inner_nf.rays() N( 1, 0, 0), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1), N(1, 1, 1) in 3d lattice N sage: outer_nf = p.normal_fan(direction='outer') sage: outer_nf.rays() N(1, 0, 0), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1), N( 1, 1, 1) in 3d lattice N
I added a 2d example testing inner, outer, and an invalid direction.
Further, it would be nice to disallow such things:
sage: outer_nf = p.normal_fan(direction='blabla')by checking that direction is one of the two allowed things (see the volume function for a similar handling).
Done.
Remove the space before the semicolon in the docstring of
normal_fan
.
Done.
comment:16 Changed 2 years ago by
Great!
Could you do one change: the backtick in the error message should be a single quote.
I would also fix the title of the ticket and the description to reflect the actual changes involved.
comment:17 Changed 2 years ago by
 Commit changed from 308dada78b84d1436dca28bd970e768d6ea6c42b to 9d20a1d2ef73c9fa4e89dc0657033191d22793fd
Branch pushed to git repo; I updated commit sha1. New commits:
9d20a1d  replaced backtick by single quote

comment:18 Changed 2 years ago by
 Description modified (diff)
 Summary changed from NormalFan: issue with inner and outer normal vectors to Make outer normal fans readily available
Replying to jipilab:
Could you do one change: the backtick in the error message should be a single quote.
Done.
I would also fix the title of the ticket and the description to reflect the actual changes involved.
Done.
comment:19 Changed 2 years ago by
The doctest still has backticks.
comment:20 Changed 2 years ago by
 Commit changed from 9d20a1d2ef73c9fa4e89dc0657033191d22793fd to 440689c758f36b80c4dd0a9a88eee5c5d60f2b22
Branch pushed to git repo; I updated commit sha1. New commits:
440689c  replaced backticks in doctest

comment:21 Changed 2 years ago by
 Reviewers changed from JeanPhilippe Labbé to JeanPhilippe Labbé, Frédéric Chapoton
 Status changed from needs_review to positive_review
ok, c'est correct
comment:22 Changed 2 years ago by
 Branch changed from u/nailuj/normalfan_outer to 440689c758f36b80c4dd0a9a88eee5c5d60f2b22
 Resolution set to fixed
 Status changed from positive_review to closed
New commits:
added direction argument to NormalFan
added outer_normal method