anchor.diff:    when not is_number(Estimated);
          not is_number(Explored);
          not is_number(Rate) ->
  -  "unknown";
  +  "...";
   estimate_completion(Estimated, Explored, Rate) ->
     Remaining = Estimated - Explored,
     Completion = round(Remaining/(Rate + 0.001)),
  
positive.code:   {Str, _NewState} = progress_content(State),
    to_stderr("~s~n", [Str]).
  
  progress_header(0) ->
    progress_header_common("");
  progress_header(_State) ->
    progress_header_common("|     SSB ").
  
  -spec progress_help() -> string().
  
  progress_help() ->
    io_lib:format(
      "Errors    : Schedulings with errors~n"
      "Explored  : Schedulings already explored~n"
      "(SSB)     : Sleep set blocked schedulings (wasted effort)~n"
      "Planned   : Schedulings that will certainly be explored~n"
      "~~ Rate    : Average rate of exploration (in schedulings/s)~n"
      "Total(?)  : Estimation of total number of schedulings (see below)~n"
      "Time(?)   : Estimated time to completion (see below)~n"
      "~n"
      "Estimations:~n"
      "The total number of schedulings is estimated from the shape of the"
      " exploration tree. It has been observed to be WITHIN ONE ORDER OF"
      " MAGNITUDE of the actual number, when using default options.~n"
      "The time to completion is estimated using the estimated remaining"
      " schedulings (Total - Explored) divided by the current Rate.~n"
      , []).
  
  progress_header_common(SSB) ->
    "    Errors |  Explored " ++ SSB ++
      "| Planned |  ~ Rate |  Total(?) | Time(?) ".
  
  progress_line(0) ->
    progress_line_common("");
  progress_line(_State) ->
    progress_line_common("-----------").
  
  progress_line_common(SSB) ->
    "-----------------------" ++ SSB ++
      "------------------------------------------".
  
  progress_content(State) ->
    #logger_state{
  
negative.code:      traces_ssb = TracesSSB,
       traces_total = TracesTotal
      } = State,
    Planned = TracesTotal - TracesExplored,
    {Rate, NewRateInfo} = update_rate(RateInfo, TracesExplored),
    EstimatedTotal =
      max(concuerror_estimator:get_estimation(Estimator), TracesTotal),
    ErrorsStr =
      if Errors =:= 0 -> "none";
         Errors < 10000 -> add_seps_to_int(Errors);
         true -> "> 10k"
      end,
    [TracesExploredStr, PlannedStr] =
      [add_seps_to_int(S) || S <- [TracesExplored, Planned]],
    SSBStr =
      if TracesSSB =:= 0 -> "";
         TracesSSB < 100000 -> io_lib:format("~8s |", [add_seps_to_int(TracesSSB)]);
         true -> io_lib:format("~8s |", ["> 100k"])
      end,
    RateStr =
      case Rate of
        0    -> "<1";
        _    -> io_lib:format("~w", [Rate])
      end,
    EstimatedTotalStr =
      if EstimatedTotal =:= unknown -> "...";
         EstimatedTotal < 10000000 -> add_seps_to_int(EstimatedTotal);
         true ->
          Low = trunc(math:log10(EstimatedTotal)),
          io_lib:format("< 10e~w", [Low + 1])
      end,
    CompletionStr = estimate_completion(EstimatedTotal, TracesExplored, Rate),
    Str =
      io_lib:format(
        "~6s |"
        "~11s |"
        "~s"
        "~8s |"
        "~4s/s |"
        "~10s |"
        "~8s",
        [ErrorsStr, TracesExploredStr, SSBStr, PlannedStr,
         RateStr, EstimatedTotalStr, CompletionStr]
       ),
    NewState = State#logger_state{rate_info = NewRateInfo},
    {Str, NewState}.
  