Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #69432 > unrolled thread

Code style query: multiple assignments in if/elif tree

Started byChris Angelico <rosuav@gmail.com>
First post2014-04-01 01:33 +1100
Last post2014-04-01 02:55 -0600
Articles 20 on this page of 37 — 11 participants

Back to article view | Back to comp.lang.python


Contents

  Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 01:33 +1100
    Re: Code style query: multiple assignments in if/elif tree Marko Rauhamaa <marko@pacujo.net> - 2014-03-31 18:40 +0300
      Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 03:03 +1100
        Re: Code style query: multiple assignments in if/elif tree Rustom Mody <rustompmody@gmail.com> - 2014-03-31 09:20 -0700
          Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 03:29 +1100
            Re: Code style query: multiple assignments in if/elif tree "Rhodri James" <rhodri@wildebst.org.uk> - 2014-03-31 21:31 +0100
      Re: Code style query: multiple assignments in if/elif tree Ned Batchelder <ned@nedbatchelder.com> - 2014-03-31 17:42 -0400
      Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 09:50 +1100
      Re: Code style query: multiple assignments in if/elif tree Ben Finney <ben+python@benfinney.id.au> - 2014-04-01 09:57 +1100
      Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 10:12 +1100
        Re: Code style query: multiple assignments in if/elif tree Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-04-01 00:57 +0000
      Re: Code style query: multiple assignments in if/elif tree Ethan Furman <ethan@stoneleaf.us> - 2014-03-31 17:30 -0700
    Re: Code style query: multiple assignments in if/elif tree Steven D'Aprano <steve@pearwood.info> - 2014-04-01 04:26 +0000
      Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 16:01 +1100
        Re: Code style query: multiple assignments in if/elif tree Steven D'Aprano <steve@pearwood.info> - 2014-04-01 07:20 +0000
          Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 18:35 +1100
            Re: Code style query: multiple assignments in if/elif tree Steven D'Aprano <steve@pearwood.info> - 2014-04-01 08:07 +0000
              Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 19:12 +1100
          Re: Code style query: multiple assignments in if/elif tree Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-01 02:18 -0600
          Re: Code style query: multiple assignments in if/elif tree Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-01 02:24 -0600
      Re: Code style query: multiple assignments in if/elif tree Rustom Mody <rustompmody@gmail.com> - 2014-03-31 22:45 -0700
        Re: Code style query: multiple assignments in if/elif tree David Hutto <dwightdhutto@gmail.com> - 2014-04-01 02:05 -0400
        Re: Code style query: multiple assignments in if/elif tree Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-01 00:28 -0600
      Re: Code style query: multiple assignments in if/elif tree Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-01 00:13 -0600
      Re: Code style query: multiple assignments in if/elif tree David Hutto <dwightdhutto@gmail.com> - 2014-04-01 02:24 -0400
      Re: Code style query: multiple assignments in if/elif tree Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-01 00:39 -0600
      Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 17:55 +1100
        Re: Code style query: multiple assignments in if/elif tree Steven D'Aprano <steve@pearwood.info> - 2014-04-01 07:29 +0000
          Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 18:49 +1100
          Re: Code style query: multiple assignments in if/elif tree Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-01 02:29 -0600
          Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 19:56 +1100
      Re: Code style query: multiple assignments in if/elif tree David Hutto <dwightdhutto@gmail.com> - 2014-04-01 03:21 -0400
      Re: Code style query: multiple assignments in if/elif tree Chris Angelico <rosuav@gmail.com> - 2014-04-01 18:26 +1100
      Re: Code style query: multiple assignments in if/elif tree David Hutto <dwightdhutto@gmail.com> - 2014-04-01 03:34 -0400
      Re: Code style query: multiple assignments in if/elif tree David Hutto <dwightdhutto@gmail.com> - 2014-04-01 03:39 -0400
      Re: Code style query: multiple assignments in if/elif tree David Hutto <dwightdhutto@gmail.com> - 2014-04-01 03:46 -0400
      Re: Code style query: multiple assignments in if/elif tree Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-01 02:55 -0600

Page 1 of 2  [1] 2  Next page →


#69432 — Code style query: multiple assignments in if/elif tree

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 01:33 +1100
SubjectCode style query: multiple assignments in if/elif tree
Message-ID<mailman.8744.1396276875.18130.python-list@python.org>
Call this a code review request, if you like. I'm wondering how you'd
go about coding something like this.

Imagine you're in a train, and the brakes don't apply instantly. The
definition, in the interests of passenger comfort, is that the first
second of brake application has an acceleration of 0.2 m/s/s, the next
second has 0.425 m/s/s, and thereafter full effect of 0.85 m/s/s. You
have a state variable that says whether the brakes have just been
applied, have already been applied for at least two seconds, or
haven't yet been applied at all. Problem: Work out how far you'll go
before the brakes reach full power, and how fast you'll be going at
that point.

Here's how I currently have the code. The variable names are a tad
long, as this was also part of me teaching my brother Python.

# Already got the brakes fully on
if mode=="Brake2": distance_to_full_braking_power, speed_full_brake =
0.0, curspeed
# The brakes went on one second ago, they're nearly full
elif mode=="Brake1": distance_to_full_braking_power, speed_full_brake
= curspeed - 0.2125, curspeed - 0.425
# Brakes aren't on.
else: distance_to_full_braking_power, speed_full_brake = (curspeed -
0.1) + (curspeed - 0.4125), curspeed - 0.625
# If we hit the brakes now (or already have hit them), we'll go
another d meters and be going at s m/s before reaching full braking
power.

But I don't like the layout. I could change it to a single assignment
with expression-if, but that feels awkward too. How would you lay this
out?

(Note that the "else" case could have any of several modes in it, so I
can't so easily use a dict.)

ChrisA

[toc] | [next] | [standalone]


#69433

FromMarko Rauhamaa <marko@pacujo.net>
Date2014-03-31 18:40 +0300
Message-ID<874n2ecr5x.fsf@elektro.pacujo.net>
In reply to#69432
Chris Angelico <rosuav@gmail.com>:

> Call this a code review request, if you like. I'm wondering how you'd
> go about coding something like this.

As a simple layout question, I'd do it like this:

========================================================================
if mode == "Brake2":
    # Already got the brakes fully on
    distance_to_full_braking_power = 0.0
    speed_full_brake = curspeed
elif mode == "Brake1":
    # The brakes went on one second ago, they're nearly full
    distance_to_full_braking_power = curspeed - 0.2125
    speed_full_brake = curspeed - 0.425
else:
    # Brakes aren't on.
    distance_to_full_braking_power = (curspeed - 0.1) + (curspeed - 0.4125)
    speed_full_brake = curspeed - 0.625

# If we hit the brakes now (or already have hit them), we'll go another
# d meters and be going at s m/s before reaching full braking power.
========================================================================


Marko

[toc] | [prev] | [next] | [standalone]


#69434

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 03:03 +1100
Message-ID<mailman.8745.1396281843.18130.python-list@python.org>
In reply to#69433
On Tue, Apr 1, 2014 at 2:40 AM, Marko Rauhamaa <marko@pacujo.net> wrote:
> As a simple layout question, I'd do it like this:
>
> ========================================================================
> if mode == "Brake2":
>     # Already got the brakes fully on
>     distance_to_full_braking_power = 0.0
>     speed_full_brake = curspeed
> elif mode == "Brake1":
>     # The brakes went on one second ago, they're nearly full
>     distance_to_full_braking_power = curspeed - 0.2125
>     speed_full_brake = curspeed - 0.425
> else:
>     # Brakes aren't on.
>     distance_to_full_braking_power = (curspeed - 0.1) + (curspeed - 0.4125)
>     speed_full_brake = curspeed - 0.625
>
> # If we hit the brakes now (or already have hit them), we'll go another
> # d meters and be going at s m/s before reaching full braking power.
> ========================================================================

No particular advantage over the current version - it doesn't simplify
it any, all you've done is break it across more lines.

(The unpacking may not be ideal; as I said, this was a vehicle for
teaching oddments of Python, so I used multiple assignment partly for
the sake of using it.)

Incidentally, if you want to see the code in context, it's here:

https://github.com/Rosuav/runningtime/blob/master/runningtime.py

ChrisA

[toc] | [prev] | [next] | [standalone]


#69435

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-31 09:20 -0700
Message-ID<6775d115-a592-4082-a427-5789e1dd2875@googlegroups.com>
In reply to#69434
On Monday, March 31, 2014 9:33:54 PM UTC+5:30, Chris Angelico wrote:
> On Tue, Apr 1, 2014 at 2:40 AM, Marko Rauhamaa wrote:
> > As a simple layout question, I'd do it like this:
> > ========================================================================
> > if mode == "Brake2":
> >     # Already got the brakes fully on
> >     distance_to_full_braking_power = 0.0
> >     speed_full_brake = curspeed
> > elif mode == "Brake1":
> >     # The brakes went on one second ago, they're nearly full
> >     distance_to_full_braking_power = curspeed - 0.2125
> >     speed_full_brake = curspeed - 0.425
> > else:
> >     # Brakes aren't on.
> >     distance_to_full_braking_power = (curspeed - 0.1) + (curspeed - 0.4125)
> >     speed_full_brake = curspeed - 0.625
> > # If we hit the brakes now (or already have hit them), we'll go another
> > # d meters and be going at s m/s before reaching full braking power.
> > ========================================================================

> No particular advantage over the current version - it doesn't simplify
> it any, all you've done is break it across more lines.

Not answering your original question but the above comment

Your version was sufficiently garbled indentation-wise (it may give you sweet
pleasure to know my 'client' is GG) that I gave up on reading it.

Marko's version was clear enough that it seems to match your spec
[Ive not really verified it word for word... Just sayin']

On the whole I prefer multiple assignments.
Maybe in this case use small variable names with
separate(d) explanatory comments??

[toc] | [prev] | [next] | [standalone]


#69436

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 03:29 +1100
Message-ID<mailman.8746.1396283403.18130.python-list@python.org>
In reply to#69435
On Tue, Apr 1, 2014 at 3:20 AM, Rustom Mody <rustompmody@gmail.com> wrote:
> On the whole I prefer multiple assignments.
> Maybe in this case use small variable names with
> separate(d) explanatory comments??

Shorter variable names would certainly be the more normal, heh. I let
my brother do that part of the typing, picking names and so on. Better
for teaching to let the victi-- err, the student have the power to
choose. :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#69446

From"Rhodri James" <rhodri@wildebst.org.uk>
Date2014-03-31 21:31 +0100
Message-ID<op.xdlsnlqv5079vu@gnudebeest>
In reply to#69436
On Mon, 31 Mar 2014 17:29:54 +0100, Chris Angelico <rosuav@gmail.com>  
wrote:

> On Tue, Apr 1, 2014 at 3:20 AM, Rustom Mody <rustompmody@gmail.com>  
> wrote:
>> On the whole I prefer multiple assignments.
>> Maybe in this case use small variable names with
>> separate(d) explanatory comments??
>
> Shorter variable names would certainly be the more normal, heh. I let
> my brother do that part of the typing, picking names and so on. Better
> for teaching to let the victi-- err, the student have the power to
> choose. :)

Not just more normal, but more readable too.  The trouble with your  
original example was that the lines were too long (even ignoring the  
trouble line-wrapping caused in your post) to take in with only a couple  
of eye movements along the line.  That makes a really quite surprising  
difference to the comprehensibility of the whole thing.


-- 
Rhodri James *-* Wildebeest Herder to the Masses

[toc] | [prev] | [next] | [standalone]


#69450

FromNed Batchelder <ned@nedbatchelder.com>
Date2014-03-31 17:42 -0400
Message-ID<mailman.8755.1396302172.18130.python-list@python.org>
In reply to#69433
On 3/31/14 12:03 PM, Chris Angelico wrote:
> Incidentally, if you want to see the code in context, it's here:
>
> https://github.com/Rosuav/runningtime/blob/master/runningtime.py
>
> ChrisA

I know you didn't ask about these aspects, but they jumped out at me: 
tabs for indentation instead of spaces, and docstring-style comments in 
places that aren't docstrings.  These seem like unusual choices.

-- 
Ned Batchelder, http://nedbatchelder.com

[toc] | [prev] | [next] | [standalone]


#69452

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 09:50 +1100
Message-ID<mailman.8757.1396306245.18130.python-list@python.org>
In reply to#69433
On Tue, Apr 1, 2014 at 8:42 AM, Ned Batchelder <ned@nedbatchelder.com> wrote:
> On 3/31/14 12:03 PM, Chris Angelico wrote:
>>
>> Incidentally, if you want to see the code in context, it's here:
>>
>> https://github.com/Rosuav/runningtime/blob/master/runningtime.py
>>
>> ChrisA
>
>
> I know you didn't ask about these aspects, but they jumped out at me: tabs
> for indentation instead of spaces, and docstring-style comments in places
> that aren't docstrings.  These seem like unusual choices.

Tabs instead of spaces? They're plenty common enough, but I am *not*
getting into that debate now. The file's perfectly consistent - aside
from inside strings, all indentation is done with tabs, one per level.

How do you go about doing multi-line comments? I know I've seen other
code using triple-quoted strings for long comments before.

ChrisA

[toc] | [prev] | [next] | [standalone]


#69453

FromBen Finney <ben+python@benfinney.id.au>
Date2014-04-01 09:57 +1100
Message-ID<mailman.8758.1396306668.18130.python-list@python.org>
In reply to#69433
Chris Angelico <rosuav@gmail.com> writes:

> How do you go about doing multi-line comments? I know I've seen other
> code using triple-quoted strings for long comments before.

Just use a sequence of one-line comments::

    # Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut a
    # sapien tempor, suscipit orci sed, elementum nisl. Suspendisse at
    # lacus ut diam dignissim lobortis ac vitae augue.
    #
    # Phasellus bibendum neque a justo vulputate, quis accumsan quam
    # egestas. Etiam aliquet blandit ante sit amet cursus.

A decent code editor (e.g. Emacs, Vim) will allow manipulation of
a sequence of one-line comments in Python's comment style, and allow
treating it as a paragraphs for purposes such as re-wrapping the lines.

I agree with others that triple-quoted strings are best reserved for
string literals (including docstrings), not comments.

-- 
 \         “Alternative explanations are always welcome in science, if |
  `\   they are better and explain more. Alternative explanations that |
_o__) explain nothing are not welcome.” —Victor J. Stenger, 2001-11-05 |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#69454

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 10:12 +1100
Message-ID<mailman.8759.1396307562.18130.python-list@python.org>
In reply to#69433
On Tue, Apr 1, 2014 at 9:57 AM, Ben Finney <ben+python@benfinney.id.au> wrote:
> Chris Angelico <rosuav@gmail.com> writes:
>
>> How do you go about doing multi-line comments? I know I've seen other
>> code using triple-quoted strings for long comments before.
>
> Just use a sequence of one-line comments::
>
>     # Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut a
>     # sapien tempor, suscipit orci sed, elementum nisl. Suspendisse at
>     # lacus ut diam dignissim lobortis ac vitae augue.
>     #
>     # Phasellus bibendum neque a justo vulputate, quis accumsan quam
>     # egestas. Etiam aliquet blandit ante sit amet cursus.
>
> A decent code editor (e.g. Emacs, Vim) will allow manipulation of
> a sequence of one-line comments in Python's comment style, and allow
> treating it as a paragraphs for purposes such as re-wrapping the lines.
>
> I agree with others that triple-quoted strings are best reserved for
> string literals (including docstrings), not comments.

Fair enough. I can't remember where (or when!) it was that I learned
triple-quoted strings were appropriately abused as comments, so I've
just done a quick re-layout into hash comments.

ChrisA

[toc] | [prev] | [next] | [standalone]


#69459

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-04-01 00:57 +0000
Message-ID<533a0edd$0$29994$c3e8da3$5496439d@news.astraweb.com>
In reply to#69454
On Tue, 01 Apr 2014 10:12:38 +1100, Chris Angelico wrote:
[...]
>> I agree with others that triple-quoted strings are best reserved for
>> string literals (including docstrings), not comments.
> 
> Fair enough. I can't remember where (or when!) it was that I learned
> triple-quoted strings were appropriately abused as comments, so I've
> just done a quick re-layout into hash comments.

Probably here :-)

But note the emphasis on "abused". The only time I would use triple-
quoted strings as comments is if I wanted to quickly comment out a 
section of code:

do_this()
do_that()
'''
def do_something_else():
    """Docstring"""
    pass
do_something_else()
'''
do_more()
do_less()


sort of thing. (Note the cunning use of ''' instead of """.) But I 
wouldn't leave it like that in production code.

It's *tempting* to use """ to mark out a large block of text, and I 
wouldn't say that doing so was wrong, but it's a bit different, and 
programmers are very like cats: they don't like different.


-- 
Steven D'Aprano
http://import-that.dreamwidth.org/

[toc] | [prev] | [next] | [standalone]


#69458

FromEthan Furman <ethan@stoneleaf.us>
Date2014-03-31 17:30 -0700
Message-ID<mailman.8763.1396313500.18130.python-list@python.org>
In reply to#69433
On 03/31/2014 04:12 PM, Chris Angelico wrote:
> On Tue, Apr 1, 2014 at 9:57 AM, Ben Finney <ben+python@benfinney.id.au> wrote:
>> Chris Angelico <rosuav@gmail.com> writes:
>>
>>> How do you go about doing multi-line comments? I know I've seen other
>>> code using triple-quoted strings for long comments before.
>>
>> Just use a sequence of one-line comments::
>>
>>      # Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut a
>>      # sapien tempor, suscipit orci sed, elementum nisl. Suspendisse at
>>      # lacus ut diam dignissim lobortis ac vitae augue.
>>      #
>>      # Phasellus bibendum neque a justo vulputate, quis accumsan quam
>>      # egestas. Etiam aliquet blandit ante sit amet cursus.
>>
>> A decent code editor (e.g. Emacs, Vim) will allow manipulation of
>> a sequence of one-line comments in Python's comment style, and allow
>> treating it as a paragraphs for purposes such as re-wrapping the lines.
>>
>> I agree with others that triple-quoted strings are best reserved for
>> string literals (including docstrings), not comments.
>
> Fair enough. I can't remember where (or when!) it was that I learned
> triple-quoted strings were appropriately abused as comments, so I've
> just done a quick re-layout into hash comments.

Personally, I use the sequence of one-line comments.

But, hey, Guido [1] himself likes the triple-quoted string as comment feature [2], so feel free to use it yourself if 
you like.

--
~Ethan~

[1] https://mail.python.org/pipermail/python-dev/2013-March/124947.html
[2] https://mail.python.org/pipermail/python-ideas/2009-October/006204.html

[toc] | [prev] | [next] | [standalone]


#69466

FromSteven D'Aprano <steve@pearwood.info>
Date2014-04-01 04:26 +0000
Message-ID<533a3fd8$0$2909$c3e8da3$76491128@news.astraweb.com>
In reply to#69432
On Tue, 01 Apr 2014 01:33:09 +1100, Chris Angelico wrote:

> Call this a code review request, if you like. I'm wondering how you'd go
> about coding something like this.

I wouldn't. I'd start off by analysing the problem, and putting it into 
the simplest format possible, and *then* start writing code if and only 
if needed. See below.

The first mistake of computational mathematics is to do the computation 
before the mathematics, and the Holy Grail is to avoid the computation 
altogether.

 
> Imagine you're in a train, and the brakes don't apply instantly. The
> definition, in the interests of passenger comfort, 

Ah, you're using comfort in the modern sense, i.e. what people used to 
call discomfort :-P

The scenario you describe has (effectively) infinite rate-of-change-of-
acceleration, often called "jerk". (A jerk is a rapid change in 
acceleration.) Human comfort is (within reasonable limits) more affected 
by jerk than acceleration. The passengers will feel three quite 
distinctive jerks, one when the brakes are first applied (which is 
probably reasonable), then one at 1s, then again at 2s. That's not 
comfortable by any stretch of the imagination.


> is that the first
> second of brake application has an acceleration of 0.2 m/s/s, the next
> second has 0.425 m/s/s, and thereafter full effect of 0.85 m/s/s. 

In mathematics, this is called  hybrid function, and is usually written 
like this:

         g(t) for t < 0
f(t) = { 42 for t == 0
         h(t) for t > 0

or something similar. (The opening brace { ought to be large enough to 
cover all three lines, and there is no closing brace.)

In your case, you have three constant functions.


> You
> have a state variable that says whether the brakes have just been
> applied, have already been applied for at least two seconds, or haven't
> yet been applied at all. 

I wouldn't model it that way. Especially since you've missed at least one 
state :-) I'd model the acceleration as a function of time, otherwise you 
have to convert a time into a state. Nevertheless, if you insist, we can 
use a state variable instead:

          0 for state == "BRAKES NOT APPLIED YET"
accel = { 0.2 for state == "BRAKES ON FOR BETWEEN 0 AND 1 SECOND"
          0.425 for STATE == BRAKES ON FOR BETWEEN 1 AND 2 SECOND"
          0.85 for state == "BRAKES ON FOR MORE THAN 2 SECONDS"

Implied, but not stated, is that once the train stops, acceleration also 
goes to zero -- the train does not start moving backwards.

Haskell has nifty pattern-matching syntax for this that looks quite close 
to the mathematical hybrid function syntax, but in Python, we're limited 
to explicitly using an if. If I were coding this, and I'm not, I'd wrap 
it in a function. One advantage of a state variable rather than a 
continuous time function is that we can do this:

def accel(state):
    return {NO_BRAKING: 0.0,
            LOW_BRAKING: 0.2,
            MID_BRAKING: 0.425,
            HIGH_BRAKING: 0.85}[state]


which is simple enough to skip using a function in the first place, and 
just use the dict lookup directly. But for a more general question you'll 
want acceleration as a function of time.

If you prefer if...elif over a dict, I'd still hide it in a function.


> Problem: Work out how far you'll go before the
> brakes reach full power, and how fast you'll be going at that point.

Given that problem, we actually only care about LOW_BRAKING and 
MID_BRAKING. The problem becomes quite simple:

At t=0, the train is travelling at u m/s and the brakes are applied with 
acceleration of 0.2m/s^2 for one second, then 0.425m/s^2 for an 
additional one second. What is the speed of the train after those two 
seconds, and the distance travelled.

This becomes a simple question for the four standard equations of motion:

(1) v = u + at
(2) s = 1/2(u + v)t
(3) s = ut + 1/2(at^2)
(4) v^2 = u^2 + 2as

Only (1) and (3) are needed.


The distance travelled in the first second is:

    s1 = u - 0.1  m

and the speed of the train at that time becomes:

    v = u - 0.2  m/s

Applying this for the second second gives:

    s2 = (u - 0.2) - 0.2125  m

    v = (u - 0.2) - 0.425  m/s

and the total distance:

    s = s1 + s2


No programming required, just a calculator :-)

Given that solving the entire problem is barely five lines, writing code 
to do so is probably unnecessary.

The only thing I haven't done is check that the train isn't travelling so 
slowly that it comes to a complete halt within two seconds. I leave that 
as an exercise. (Hint: if the final speed is negative, the train came to 
a halt.)


> Here's how I currently have the code. The variable names are a tad long,
> as this was also part of me teaching my brother Python.

Whatever you used to post this, ate the indentation.

> # Already got the brakes fully on
> if mode=="Brake2": distance_to_full_braking_power, speed_full_brake =
> 0.0, curspeed
> # The brakes went on one second ago, they're nearly full elif
> mode=="Brake1": distance_to_full_braking_power, speed_full_brake =
> curspeed - 0.2125, curspeed - 0.425 # Brakes aren't on.
> else: distance_to_full_braking_power, speed_full_brake = (curspeed -
> 0.1) + (curspeed - 0.4125), curspeed - 0.625 # If we hit the brakes now
> (or already have hit them), we'll go another d meters and be going at s
> m/s before reaching full braking power.

Using sequence unpacking just to save a newline is naughty :-)

dist, speed = (curspeed - 0.1) + (curspeed - 0.4125), curspeed - 0.625

is an abuse of syntax, not far removed from:

dist = (curspeed - 0.1) + (curspeed - 0.4125); speed = curspeed - 0.625

It will be much more comprehensible written as two statements. 


 
> But I don't like the layout. I could change it to a single assignment
> with expression-if, but that feels awkward too. How would you lay this
> out?
> 
> (Note that the "else" case could have any of several modes in it, so I
> can't so easily use a dict.)

It could have, but doesn't. Is your aim to build a general purpose 
Newtonian linear motion solver, or to solve this one problem?


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#69467

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 16:01 +1100
Message-ID<mailman.8767.1396328509.18130.python-list@python.org>
In reply to#69466
On Tue, Apr 1, 2014 at 3:26 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> On Tue, 01 Apr 2014 01:33:09 +1100, Chris Angelico wrote:
>
>> Call this a code review request, if you like. I'm wondering how you'd go
>> about coding something like this.
>
> I wouldn't. I'd start off by analysing the problem, and putting it into
> the simplest format possible, and *then* start writing code if and only
> if needed. See below.
>
> The first mistake of computational mathematics is to do the computation
> before the mathematics, and the Holy Grail is to avoid the computation
> altogether.

Fair enough. :)

>> Imagine you're in a train, and the brakes don't apply instantly. The
>> definition, in the interests of passenger comfort,
>
> Ah, you're using comfort in the modern sense, i.e. what people used to
> call discomfort :-P
>
> The scenario you describe has (effectively) infinite rate-of-change-of-
> acceleration, often called "jerk". (A jerk is a rapid change in
> acceleration.) Human comfort is (within reasonable limits) more affected
> by jerk than acceleration. The passengers will feel three quite
> distinctive jerks, one when the brakes are first applied (which is
> probably reasonable), then one at 1s, then again at 2s. That's not
> comfortable by any stretch of the imagination.

It actually is a smooth increase in deceleration, but I'm operating
the simulator on a 1s period, so it's actually an average across the
first second, and an average across the next second...

>> is that the first
>> second of brake application has an acceleration of 0.2 m/s/s, the next
>> second has 0.425 m/s/s, and thereafter full effect of 0.85 m/s/s.

... so really, it's seeking upward from 0 to 0.85 according to some
curve, the details of which I'm not familiar with, but in terms of 1s
average accelerations, it's those figures. Actually even 1s resolution
is more than we need; the overall purpose is to get a calculated time
in minutes, so calculating to sub-second resolution (when, in reality,
this is trying to predict what a human will do) is massive overkill.

>> You
>> have a state variable that says whether the brakes have just been
>> applied, have already been applied for at least two seconds, or haven't
>> yet been applied at all.
>
> I wouldn't model it that way. Especially since you've missed at least one
> state :-) I'd model the acceleration as a function of time, otherwise you
> have to convert a time into a state. Nevertheless, if you insist, we can
> use a state variable instead:
>
>           0 for state == "BRAKES NOT APPLIED YET"
> accel = { 0.2 for state == "BRAKES ON FOR BETWEEN 0 AND 1 SECOND"
>           0.425 for STATE == BRAKES ON FOR BETWEEN 1 AND 2 SECOND"
>           0.85 for state == "BRAKES ON FOR MORE THAN 2 SECONDS"
>
> Implied, but not stated, is that once the train stops, acceleration also
> goes to zero -- the train does not start moving backwards.

"Just been applied" is poorly named; that's the state where the brakes
have been applied for 1 second so far. The other state (brakes not
applied yet) could be looking at powering (which follows a similar
curve in the opposite direction) or cruising (which has acceleration
of 0.0 m/s/s).

> Haskell has nifty pattern-matching syntax for this that looks quite close
> to the mathematical hybrid function syntax, but in Python, we're limited
> to explicitly using an if. If I were coding this, and I'm not, I'd wrap
> it in a function. One advantage of a state variable rather than a
> continuous time function is that we can do this:
>
> def accel(state):
>     return {NO_BRAKING: 0.0,
>             LOW_BRAKING: 0.2,
>             MID_BRAKING: 0.425,
>             HIGH_BRAKING: 0.85}[state]

That could be done, but with .get() to allow a default. I may well do that.

>> Problem: Work out how far you'll go before the
>> brakes reach full power, and how fast you'll be going at that point.
>
> Given that problem, we actually only care about LOW_BRAKING and
> MID_BRAKING. The problem becomes quite simple:

Right. The other state is "zero distance and zero loss of speed".

> At t=0, the train is travelling at u m/s and the brakes are applied with
> acceleration of 0.2m/s^2 for one second, then 0.425m/s^2 for an
> additional one second. What is the speed of the train after those two
> seconds, and the distance travelled.
>
> This becomes a simple question for the four standard equations of motion:
>
> (1) v = u + at
> (2) s = 1/2(u + v)t
> (3) s = ut + 1/2(at^2)
> (4) v^2 = u^2 + 2as
>
> Only (1) and (3) are needed.

Okay, what's u here? Heh.

> The distance travelled in the first second is:
>
>     s1 = u - 0.1  m
>
> and the speed of the train at that time becomes:
>
>     v = u - 0.2  m/s
>
> Applying this for the second second gives:
>
>     s2 = (u - 0.2) - 0.2125  m
>
>     v = (u - 0.2) - 0.425  m/s
>
> and the total distance:
>
>     s = s1 + s2
>
>
> No programming required, just a calculator :-)
>
> Given that solving the entire problem is barely five lines, writing code
> to do so is probably unnecessary.

This is one small part of a larger piece of code (which, in this
instance, is trying to answer this question: "If I apply the brakes
now and keep them on until the next curve, will I be way below the
curve's speed limit?" - if yes, don't apply the brakes now).

> The only thing I haven't done is check that the train isn't travelling so
> slowly that it comes to a complete halt within two seconds. I leave that
> as an exercise. (Hint: if the final speed is negative, the train came to
> a halt.)

Yeah. Or just let that go into the next part of the calculation, which
works out quadratically how much distance -> how much time -> how much
remaining speed, which may have no solution ie it doesn't reach that
point. That part's fine.

> Whatever you used to post this, ate the indentation.

I posted that part without indentation, yeah. Gmail eats tabs.
Normally I manually replace them with spaces for posting, but since
this whole section was at the same indentation level, I didn't bother.
It is one of the problems with Gmail, though, and if I weren't running
this account on multiple systems of different OSes, I'd probably use a
dedicated client.

>> # Already got the brakes fully on
>> if mode=="Brake2": distance_to_full_braking_power, speed_full_brake =
>> 0.0, curspeed
>> # The brakes went on one second ago, they're nearly full elif
>> mode=="Brake1": distance_to_full_braking_power, speed_full_brake =
>> curspeed - 0.2125, curspeed - 0.425 # Brakes aren't on.
>> else: distance_to_full_braking_power, speed_full_brake = (curspeed -
>> 0.1) + (curspeed - 0.4125), curspeed - 0.625 # If we hit the brakes now
>> (or already have hit them), we'll go another d meters and be going at s
>> m/s before reaching full braking power.
>
> Using sequence unpacking just to save a newline is naughty :-)
>
> dist, speed = (curspeed - 0.1) + (curspeed - 0.4125), curspeed - 0.625
>
> is an abuse of syntax, not far removed from:
>
> dist = (curspeed - 0.1) + (curspeed - 0.4125); speed = curspeed - 0.625
>
> It will be much more comprehensible written as two statements.

Fair enough. :) That's why I asked. Is it naughty enough to break into
two statements, or is it better to combine it into a single multiple
assignment?

>> But I don't like the layout. I could change it to a single assignment
>> with expression-if, but that feels awkward too. How would you lay this
>> out?
>>
>> (Note that the "else" case could have any of several modes in it, so I
>> can't so easily use a dict.)
>
> It could have, but doesn't. Is your aim to build a general purpose
> Newtonian linear motion solver, or to solve this one problem?

To solve this one problem, as part of a simulator. For any purpose
beyond what you can see in the code itself, you'd have to ask my
brother; I don't have the full details on that.

Thanks for the advice! Flamage welcome, I'm wearing the asbestos
that's just been removed from the theatre here...

ChrisA

[toc] | [prev] | [next] | [standalone]


#69478

FromSteven D'Aprano <steve@pearwood.info>
Date2014-04-01 07:20 +0000
Message-ID<533a68c3$0$2909$c3e8da3$76491128@news.astraweb.com>
In reply to#69467
On Tue, 01 Apr 2014 16:01:40 +1100, Chris Angelico wrote:

[...]
>> The scenario you describe has (effectively) infinite rate-of-change-of-
>> acceleration, often called "jerk". (A jerk is a rapid change in
>> acceleration.) Human comfort is (within reasonable limits) more
>> affected by jerk than acceleration. The passengers will feel three
>> quite distinctive jerks, one when the brakes are first applied (which
>> is probably reasonable), then one at 1s, then again at 2s. That's not
>> comfortable by any stretch of the imagination.
> 
> It actually is a smooth increase in deceleration, but I'm operating the
> simulator on a 1s period, so it's actually an average across the first
> second, and an average across the next second...

Hmmm. A 1-second resolution doesn't really sound too great to me.

Suppose the deceleration increases linearly from 0 to 0.85 m/s over two 
seconds. Averaging it in the way you suggested, we get a total distance 
of: 

    2*u - 0.5125

(see my previous post for details) where u is measured in metres per 
second. Multiply by seconds to get the units right. For a Japanese bullet 
train where u = 320 km/hr that corresponds to

    py> 2*88.888889 - 0.5125
    177.26527800000002

metres.

Now let's do it properly! Given our assumption that the deceleration is 
linear, the jerk will be constant:

    j = Δa/Δt
      = (0.85 - 0)/2
      = 0.425 m/s^3

Let's start integrating!

py> from sympy import integrate
py> from sympy.abc import t
py> j = '0.425'
py> a = integrate(j, t)
py> v = 88.888889 - integrate(a, t)
py> s = integrate(v, (t, 0, 2))
py> s
177.211111333333

compared to 177.26527800000002 calculated the rough way. That's not bad, 
only about 5cm off! Effectively, your rough calculation was accurate to 
one decimal place.

Of course, if the equation for acceleration was more complex, the 
approximation may not be anywhere near as good.


[...]
>> This becomes a simple question for the four standard equations of
>> motion:
>>
>> (1) v = u + at
>> (2) s = 1/2(u + v)t
>> (3) s = ut + 1/2(at^2)
>> (4) v^2 = u^2 + 2as
>>
>> Only (1) and (3) are needed.
> 
> Okay, what's u here? Heh.

They're *standard* equations of motion. Weren't you paying attention 
through the, oh, three years of high school where they teach this? :-P

s = displacement (distance)
t = time
u = initial velocity
v = final velocity
a = acceleration

[...]
> Fair enough. :) That's why I asked. Is it naughty enough to break into
> two statements, or is it better to combine it into a single multiple
> assignment?

Since they are unrelated assignments, of two different variables, they 
should be written as two separate assignments, not one using sequence 
unpacking.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#69483

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 18:35 +1100
Message-ID<mailman.8778.1396337762.18130.python-list@python.org>
In reply to#69478
On Tue, Apr 1, 2014 at 6:20 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> On Tue, 01 Apr 2014 16:01:40 +1100, Chris Angelico wrote:
>
> [...]
>>> The scenario you describe has (effectively) infinite rate-of-change-of-
>>> acceleration, often called "jerk". (A jerk is a rapid change in
>>> acceleration.) Human comfort is (within reasonable limits) more
>>> affected by jerk than acceleration. The passengers will feel three
>>> quite distinctive jerks, one when the brakes are first applied (which
>>> is probably reasonable), then one at 1s, then again at 2s. That's not
>>> comfortable by any stretch of the imagination.
>>
>> It actually is a smooth increase in deceleration, but I'm operating the
>> simulator on a 1s period, so it's actually an average across the first
>> second, and an average across the next second...
>
> Hmmm. A 1-second resolution doesn't really sound too great to me.
>
> Suppose the deceleration increases linearly from 0 to 0.85 m/s over two
> seconds. Averaging it in the way you suggested, we get a total distance
> of:
>
>     2*u - 0.5125
>
> (see my previous post for details) where u is measured in metres per
> second. Multiply by seconds to get the units right. For a Japanese bullet
> train where u = 320 km/hr that corresponds to
>
>     py> 2*88.888889 - 0.5125
>     177.26527800000002
>
> metres.
>
> Now let's do it properly! Given our assumption that the deceleration is
> linear, the jerk will be constant:
>
>     j = Δa/Δt
>       = (0.85 - 0)/2
>       = 0.425 m/s^3
>
> Let's start integrating!
>
> py> from sympy import integrate
> py> from sympy.abc import t
> py> j = '0.425'
> py> a = integrate(j, t)
> py> v = 88.888889 - integrate(a, t)
> py> s = integrate(v, (t, 0, 2))
> py> s
> 177.211111333333
>
> compared to 177.26527800000002 calculated the rough way. That's not bad,
> only about 5cm off! Effectively, your rough calculation was accurate to
> one decimal place.

5cm when we're dealing with track distances measured in meters and
usually hundreds of them? Sounds fine to me!

> Of course, if the equation for acceleration was more complex, the
> approximation may not be anywhere near as good.

And that's the bit I can't know. I've added a comment to the code and
will toss it back to my brother - hopefully he'll either know the
answer or know where to look it up / who to ask.

> [...]
>>> This becomes a simple question for the four standard equations of
>>> motion:
>>>
>>> (1) v = u + at
>>> (2) s = 1/2(u + v)t
>>> (3) s = ut + 1/2(at^2)
>>> (4) v^2 = u^2 + 2as
>>>
>>> Only (1) and (3) are needed.
>>
>> Okay, what's u here? Heh.
>
> They're *standard* equations of motion. Weren't you paying attention
> through the, oh, three years of high school where they teach this? :-P

They're certainly the standard equations, but I learned that:

d = v₀t + at²/2

which is the same as you had, except for the names: d for distance, v₀
(V zero, that's a subscript zero if encodings or fonts kill you here)
for initial velocity (ie velocity at time zero - vₜ (that's a
subscript t, U+209C, but it isn't working in this font) is velocity at
time t, which is v₀+at), and a and t are the same as you have.

> s = displacement (distance)
> t = time
> u = initial velocity
> v = final velocity
> a = acceleration

I have to say, the one-letter variables are a lot easier to work with.
Guess I learned them the hard way, heh. Although remembering that v is
velocity is easier than remembering which of u and v is initial and
which is final.

>> Fair enough. :) That's why I asked. Is it naughty enough to break into
>> two statements, or is it better to combine it into a single multiple
>> assignment?
>
> Since they are unrelated assignments, of two different variables, they
> should be written as two separate assignments, not one using sequence
> unpacking.

Change made. Yeah, that looks a bit cleaner. Although I would prefer a
simple formula to what I have there, and I'm still not perfectly sure
it's accurate.

Advice appreciated. :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#69487

FromSteven D'Aprano <steve@pearwood.info>
Date2014-04-01 08:07 +0000
Message-ID<533a73a9$0$2909$c3e8da3$76491128@news.astraweb.com>
In reply to#69483
On Tue, 01 Apr 2014 18:35:52 +1100, Chris Angelico wrote:

> Although remembering that v is
> velocity is easier than remembering which of u and v is initial and
> which is final.

Which comes earlier in the alphabet? :-P


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#69488

FromChris Angelico <rosuav@gmail.com>
Date2014-04-01 19:12 +1100
Message-ID<mailman.8782.1396339983.18130.python-list@python.org>
In reply to#69487
On Tue, Apr 1, 2014 at 7:07 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> On Tue, 01 Apr 2014 18:35:52 +1100, Chris Angelico wrote:
>
>> Although remembering that v is
>> velocity is easier than remembering which of u and v is initial and
>> which is final.
>
> Which comes earlier in the alphabet? :-P

So why isn't v initial velocity and w final? You start with some
velocity, right?

(Okay, now I'm mostly trolling. Heh. I did say your way was better, to
start with.)

ChrisA

[toc] | [prev] | [next] | [standalone]


#69489

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-04-01 02:18 -0600
Message-ID<mailman.8783.1396340355.18130.python-list@python.org>
In reply to#69478
On Tue, Apr 1, 2014 at 1:35 AM, Chris Angelico <rosuav@gmail.com> wrote:
> On Tue, Apr 1, 2014 at 6:20 PM, Steven D'Aprano <steve@pearwood.info> wrote:
>> 177.211111333333
>>
>> compared to 177.26527800000002 calculated the rough way. That's not bad,
>> only about 5cm off! Effectively, your rough calculation was accurate to
>> one decimal place.
>
> 5cm when we're dealing with track distances measured in meters and
> usually hundreds of them? Sounds fine to me!

Erm, that's just the accumulated error over the first 2 seconds,
though.  A train moving at 88 m/s and decelerating at a maximum of
0.85 m/s^2 is not going to stop in just 177 meters.

After the first 2 seconds, the model is the same using either method,
but the velocity after 2 seconds is different.  Using the linear
deceleration integration, we get:

a(t) = {-0.425t, t <= 2;
        -0.85, t > 2}
v(t) = {v0 - 0.2125t^2, t <= 2;
        v0 - 0.85 - 0.85t, t > 2}

Giving v(2s) = v0 - 0.85 m/s

Using the averaging method, we get v(2s) = v0 - 0.2 - 0.425 = v0 - 0.625 m/s

For a difference of 0.225 m/s.  Using Steven's formula (4), the
additional difference in stopping distance is thus:

Δs = ((0 - (88.888889 - 0.625)^2) - (0 - (88.888889 - 0.85)^2)) / -1.7
     = 23.33 m

The reason the velocity is different after 2 seconds is because the
linear deceleration does not match the constraints of the problem. The
average deceleration for the first second is not 0.2 m/s, and the
average deceleration for the second second is not 0.425 m/s.

[toc] | [prev] | [next] | [standalone]


#69492

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-04-01 02:24 -0600
Message-ID<mailman.8785.1396340689.18130.python-list@python.org>
In reply to#69478
On Tue, Apr 1, 2014 at 2:18 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> The reason the velocity is different after 2 seconds is because the
> linear deceleration does not match the constraints of the problem. The
> average deceleration for the first second is not 0.2 m/s, and the
> average deceleration for the second second is not 0.425 m/s.

Which I suddenly realize after posting makes my entire point moot.  It
doesn't matter how much total error there is from the linear
deceleration method because the linear deceleration is wrong.  As long
as the averaging method has the actually correct velocity at 2s and thereafter
continues to have the actually correct velocity, it will only be off
by that small amount of error from the first two seconds.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.python


csiph-web