emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Carsten Dominik <carsten.dominik@gmail.com>
To: Michael Gauland <mikelygee@no8wireless.co.nz>
Cc: emacs-orgmode@gnu.org
Subject: Re: Estimate ranges in column view
Date: Wed, 30 Jun 2010 15:40:15 +0200	[thread overview]
Message-ID: <1E7F9912-F266-4365-B689-9C44E06027C6@gmail.com> (raw)
In-Reply-To: <20100622.143610.09007983.mikelygee@no8wireless.co.nz>

Hi Michael,

I was about to apply the patch, but I don't think I got a reply from  
you regarding copyright issues.
Did I miss that, or did you not say anything about it?

Unfortunately the patch is larger than the maximum that I can take  
without copyright assignment.



- Carsten

On Jun 22, 2010, at 4:36 AM, Michael Gauland wrote:

> Carsten,
> Here is a patch for a new 'est+' summary type, including  
> corresponding changes for xemacs and the manual. I've done basic  
> testing on the GNU emacs version, but not the xemacs code.
>
> I'm not sure the change to the manual provides the right amount of  
> information
> in the right place; I'd be happy to re-write to make it find in
> better. Similarly, the name of the summary type is entirely up to you.
>
> I didn't know whether to send this directly to you, or to the list;  
> if it should go to the list I'd be happy to send it there directly.
>
> Thanks for the chance to contribute,
> Mike
> diff --git a/doc/org.texi b/doc/org.texi
> index 17615e0..529be4d 100644
> --- a/doc/org.texi
> +++ b/doc/org.texi
> @@ -4723,9 +4723,10 @@ optional.  The individual parts have the  
> following meaning:
>                 @{:min@}    @r{Smallest time value in column.}
>                 @{:max@}    @r{Largest time value.}
>                 @{:mean@}   @r{Arithmetic mean of time values.}
> -                @{@@min@}   @r{Minimum age (in days/hours/mins/ 
> seconds).}
> -                @{@@max@}   @r{Maximum age (in days/hours/mins/ 
> seconds).}
> -                @{@@mean@}  @r{Arithmetic mean of ages (in days/ 
> hours/mins/seconds).}
> +                @{@@min@}    @r{Minimum age (in days/hours/mins/ 
> seconds).}
> +                @{@@max@}    @r{Maximum age (in days/hours/mins/ 
> seconds).}
> +                @{@@mean@}   @r{Arithmetic mean of ages (in days/ 
> hours/mins/seconds).}
> +                @{est+@}    @r{Add low-high estimates.}
> @end example
>
> @noindent
> @@ -4733,6 +4734,22 @@ Be aware that you can only have one summary  
> type for any property you
> include. Subsequent columns referencing the same property will all  
> display the
> same summary information.
>
> +The 'est+' summary type requires further explanation. It is used for
> +combining task estimates, expressed as low-high ranges. For  
> example, instead
> +of estimating a particular task will take 5 days, you might  
> estimate it as
> +5-6 days if you're fairly confident you know how much woark is  
> required, or
> +1-10 days if you don't really know what needs to be done.  Both  
> ranges
> +average at 5.5 days, but the first represents a more predictable  
> delivery.
> +
> +When combining a set of such estimates, simply adding the lows and  
> highs
> +produces an unrealistically wide result. Instead, 'est+' adds the  
> statistical
> +mean and variance of the sub-tasks, generating a final estimate  
> from the sum.
> +For example, suppose you had ten tasks, each of which was estimated  
> at 0.5 to
> +2 days of work. Straight addition produces an estimate of 5 to 20  
> days,
> +representing what to expect if everything goes either extremely  
> well or
> +extremely poorly. In contrast, 'est+' estimates the full job more
> +realistically, at 10-15 days.
> +
> Here is an example for a complete columns definition, along with  
> allowed
> values.
>
> diff --git a/lisp/org-colview-xemacs.el b/lisp/org-colview-xemacs.el
> index 152d9fe..90bf4c4 100644
> --- a/lisp/org-colview-xemacs.el
> +++ b/lisp/org-colview-xemacs.el
> @@ -917,7 +917,8 @@ around it."
>     ("@max" max_age max (lambda (x) (- org-columns-time x)))
>     ("@mean" mean_age
>      (lambda (&rest x) (/ (apply '+ x) (float (length x))))
> -     (lambda (x) (- org-columns-time x))))
> +     (lambda (x) (- org-columns-time x)))
> +    ("est+" estimate org-estimate-combine))
>   "Operator <-> format,function,calc  map.
>  Used to compile/uncompile columns format and completing read in
>  interactive function org-columns-new.
> @@ -1206,6 +1207,7 @@ Don't set this, this is meant for dynamic  
> scoping.")
> (defun org-columns-number-to-string (n fmt &optional printf)
>   "Convert a computed column number to a string value, according to  
> FMT."
>   (cond
> +   ((memq fmt '(estimate)) (org-estimate-print n printf))
>    ((not (numberp n)) "")
>    ((memq fmt '(add_times max_times min_times mean_times))
>     (let* ((h (floor n)) (m (floor (+ 0.5 (* 60 (- n h))))))
> @@ -1250,9 +1252,9 @@ Don't set this, this is meant for dynamic  
> scoping.")
> 	    (setq sum (+ (string-to-number (pop l)) (/ sum 60))))
> 	  sum))
>        ((memq fmt '(checkbox checkbox-n-of-m checkbox-percent))
> -	(if (equal s "[X]") 1. 0.000001))
> -       (t (string-to-number s)))
> -    0))
> +        (if (equal s "[X]") 1. 0.000001))
> +       ((memq fmt '(estimate)) (org-string-to-estimate s))
> +       (t (string-to-number s)))))
>
> (defun org-columns-uncompile-format (cfmt)
>   "Turn the compiled columns format back into a string  
> representation."
> @@ -1693,6 +1695,42 @@ This will add overlays to the date lines, to  
> show the summary for each day."
>       (format "%dd %02dh %02dm %02ds" days hours minutes seconds))
>     ""))
>
> +(defun org-estimate-mean-and-var (v)
> +  "Return the mean and variance of an estimate."
> +  (let* ((low (float (car v)))
> +         (high (float (cadr v)))
> +         (mean (/ (+ low high) 2.0))
> +         (var (/ (+ (expt (- mean low) 2.0) (expt (- high mean)  
> 2.0)) 2.0)))
> +    (list  mean var)
> +    ))
> +
> +(defun org-estimate-combine (&rest el)
> +  "Combine a list of estimates, using mean and variance.
> +The mean and variance of the result will be the sum of the means
> +and variances (respectively) of the individual estimates."
> +  (let ((mean 0)
> +        (var 0))
> +    (mapc (lambda (e)
> +	    (let ((stats (org-estimate-mean-and-var e)))
> +	      (setq mean (+ mean (car stats)))
> +	      (setq var (+ var (cadr stats)))))
> +	  el)
> +    (let ((stdev (sqrt var)))
> +      (list (- mean stdev) (+ mean stdev)))
> +    ))
> +
> +(defun org-estimate-print (e &optional fmt)
> +  "Prepare a string representation of an estimate, as two numbers  
> with a '-' in between them."
> +  (if (null fmt) (set 'fmt "%.0f"))
> +  (format "%s" (mapconcat (lambda (n) (format fmt n))  e "-")))
> +
> +(defun org-string-to-estimate (s)
> +  "Convert a string to an estimate. The string should be two  
> numbers joined with a '-'."
> +  (if (string-match "\\(.*\\)-\\(.*\\)" s)
> +      (list (string-to-number (match-string 1 s)) (string-to- 
> number(match-string 2 s)))
> +    (list (string-to-number s) (string-to-number s))
> +    ))
> +
>
> (provide 'org-colview)
> (provide 'org-colview-xemacs)
> diff --git a/lisp/org-colview.el b/lisp/org-colview.el
> index c820be0..af7eef5 100644
> --- a/lisp/org-colview.el
> +++ b/lisp/org-colview.el
> @@ -746,7 +746,8 @@ around it."
>     ("@max" max_age max (lambda (x) (- org-columns-time x)))
>     ("@mean" mean_age
>      (lambda (&rest x) (/ (apply '+ x) (float (length x))))
> -     (lambda (x) (- org-columns-time x))))
> +     (lambda (x) (- org-columns-time x)))
> +    ("est+" estimate org-estimate-combine))
>   "Operator <-> format,function,calc  map.
> Used to compile/uncompile columns format and completing read in
> interactive function org-columns-new.
> @@ -1031,6 +1032,7 @@ Don't set this, this is meant for dynamic  
> scoping.")
> (defun org-columns-number-to-string (n fmt &optional printf)
>   "Convert a computed column number to a string value, according to  
> FMT."
>   (cond
> +   ((memq fmt '(estimate)) (org-estimate-print n printf))
>    ((not (numberp n)) "")
>    ((memq fmt '(add_times max_times min_times mean_times))
>     (let* ((h (floor n)) (m (floor (+ 0.5 (* 60 (- n h))))))
> @@ -1054,28 +1056,30 @@ Don't set this, this is meant for dynamic  
> scoping.")
>       (format "[%d/%d]" n m)
>     (format "[%d%%]"(floor (+ 0.5 (* 100. (/ (* 1.0 n) m)))))))
>
> +
> (defun org-columns-string-to-number (s fmt)
>   "Convert a column value to a number that can be used for column  
> computing."
>   (if s
>       (cond
>        ((memq fmt '(min_age max_age mean_age))
> -	(cond ((string= s "") org-columns-time)
> -	      ((string-match
> -		"\\([0-9]+\\)d \\([0-9]+\\)h \\([0-9]+\\)m \\([0-9]+\\)s"
> -		s)
> -	       (+ (* 60 (+ (* 60 (+ (* 24 (string-to-number (match-string  
> 1 s)))
> -				    (string-to-number (match-string 2 s))))
> -			   (string-to-number (match-string 3 s))))
> -		  (string-to-number (match-string 4 s))))
> -	      (t (time-to-number-of-days (apply 'encode-time
> -						(org-parse-time-string s t))))))
> +        (cond ((string= s "") org-columns-time)
> +              ((string-match
> +                "\\([0-9]+\\)d \\([0-9]+\\)h \\([0-9]+\\)m \\([0-9]+ 
> \\)s"
> +                s)
> +               (+ (* 60 (+ (* 60 (+ (* 24 (string-to-number (match- 
> string 1 s)))
> +                                    (string-to-number (match-string  
> 2 s))))
> +                           (string-to-number (match-string 3 s))))
> +                  (string-to-number (match-string 4 s))))
> +              (t (time-to-number-of-days (apply 'encode-time
> +                                                (org-parse-time- 
> string s t))))))
>        ((string-match ":" s)
> -	(let ((l (nreverse (org-split-string s ":"))) (sum 0.0))
> -	  (while l
> -	    (setq sum (+ (string-to-number (pop l)) (/ sum 60))))
> -	  sum))
> +        (let ((l (nreverse (org-split-string s ":"))) (sum 0.0))
> +          (while l
> +            (setq sum (+ (string-to-number (pop l)) (/ sum 60))))
> +          sum))
>        ((memq fmt '(checkbox checkbox-n-of-m checkbox-percent))
> -	(if (equal s "[X]") 1. 0.000001))
> +        (if (equal s "[X]") 1. 0.000001))
> +       ((memq fmt '(estimate)) (org-string-to-estimate s))
>        (t (string-to-number s)))))
>
> (defun org-columns-uncompile-format (cfmt)
> @@ -1492,6 +1496,43 @@ This will add overlays to the date lines, to  
> show the summary for each day."
>       (format "%dd %02dh %02dm %02ds" days hours minutes seconds))
>     ""))
>
> +(defun org-estimate-mean-and-var (v)
> +  "Return the mean and variance of an estimate."
> +  (let* ((low (float (car v)))
> +         (high (float (cadr v)))
> +         (mean (/ (+ low high) 2.0))
> +         (var (/ (+ (expt (- mean low) 2.0) (expt (- high mean)  
> 2.0)) 2.0)))
> +    (list  mean var)
> +    ))
> +
> +(defun org-estimate-combine (&rest el)
> +  "Combine a list of estimates, using mean and variance.
> +The mean and variance of the result will be the sum of the means
> +and variances (respectively) of the individual estimates."
> +  (let ((mean 0)
> +        (var 0))
> +    (mapc (lambda (e)
> +              (let ((stats (org-estimate-mean-and-var e)))
> +                (setq mean (+ mean (car stats)))
> +                (setq var (+ var (cadr stats)))))
> +            el)
> +    (let ((stdev (sqrt var)))
> +      (list (- mean stdev) (+ mean stdev)))
> +    ))
> +
> +(defun org-estimate-print (e &optional fmt)
> +  "Prepare a string representation of an estimate, as two numbers  
> with a '-' in between them."
> +  (if (null fmt) (set 'fmt "%.0f"))
> +  (format "%s" (mapconcat (lambda (n) (format fmt n))  e "-"))
> +  )
> +
> +(defun org-string-to-estimate (s)
> +  "Convert a string to an estimate. The string should be two  
> numbers joined with a '-'."
> +  (if (string-match "\\(.*\\)-\\(.*\\)" s)
> +      (list (string-to-number (match-string 1 s)) (string-to- 
> number(match-string 2 s)))
> +    (list (string-to-number s) (string-to-number s))
> +    ))
> +
>
> (provide 'org-colview)
>

- Carsten

  reply	other threads:[~2010-06-30 13:40 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-17 20:06 Estimate ranges in column view Mike Gauland
2010-06-18  7:04 ` Carsten Dominik
2010-06-22  2:36   ` Michael Gauland
2010-06-30 13:40     ` Carsten Dominik [this message]
2010-06-30 18:19       ` Michael Gauland
2010-06-30 20:29         ` Juan
2010-07-01  7:55         ` Carsten Dominik
2010-07-19 11:57     ` Patchwork: Patch 65 Accepted Carsten Dominik
2010-07-19 12:03     ` Estimate ranges in column view Carsten Dominik
2010-07-20  9:53       ` Michael Gauland
     [not found]       ` <BC256B00-E893-4B6D-8C0D-855F7ADFF093-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2011-11-15 15:14         ` Sebastien Vauban
2011-11-24 15:44           ` Sebastien Vauban

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1E7F9912-F266-4365-B689-9C44E06027C6@gmail.com \
    --to=carsten.dominik@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    --cc=mikelygee@no8wireless.co.nz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).