text:
!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.CommandJS=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
/// <reference path="../../typings/commandjs/command-definitions.d.ts"/>
var CommandJS;
(function (CommandJS) {
    "use strict";
    var states = _dereq_('./states');
    var commandParser = _dereq_('./command-parser');
    var CommandExecutorImpl = (function () {
        function CommandExecutorImpl(commands) {
            if (commands && !(commands instanceof Array)) {
                throw 'An array of commands is required';
            }
            this.commands = this.prepareCommands(commands);
        }
        CommandExecutorImpl.prototype.getCommands = function () {
            return this.commands;
        };
        CommandExecutorImpl.prototype.execute = function (commandString) {
            var parsed = this.parse(commandString);
            var commandParts = this.getCommandParts(parsed);
            if (!commandParts) {
                return {
                    state: states.ExecutorResponseState.ERROR,
                    errorType: states.ExecutorErrorType.PARSER_ERROR,
                    commandString: commandString
                };
            }
            var commandResponse = this.findCommand(commandParts, true);
            if (commandResponse.state === states.ExecutorResponseState.ERROR) {
                commandResponse.commandString = commandString;
                return commandResponse;
            }
            try {
                return commandResponse.response;
            }
            catch (e) {
                return {
                    state: states.ExecutorResponseState.ERROR,
                    errorType: states.ExecutorErrorType.COMMAND_EXECUTION_ERROR,
                    commandString: commandString,
                    response: e
                };
            }
        };
        CommandExecutorImpl.prototype.getCommand = function (commandString) {
            var commandParts = this.getCommandParts(this.parse(commandString));
            if (!commandParts) {
                return {
                    state: states.ExecutorResponseState.ERROR,
                    errorType: states.ExecutorErrorType.PARSER_ERROR,
                    commandString: commandString
                };
            }
            var commandResponse = this.findCommand(commandParts, false);
            commandResponse.commandString = commandString;
            return commandResponse;
        };
        CommandExecutorImpl.prototype.findCommand = function (commandParts, paramsAllowed) {
            if (!commandParts) {
                return null;
            }
            var actualCommand;
            var current = this.commands;
            var i;
            var part;
            for (i in commandParts) {
                part = commandParts[i];
                if (current[part]) {
                    actualCommand = current[part];
                    if (actualCommand.subCommands) {
                        current = actualCommand.subCommands;
                    }
                    else if (!paramsAllowed && i < commandParts.length - 1) {
                        return {
                            state: states.ExecutorResponseState.ERROR,
                            errorType: states.ExecutorErrorType.COMMAND_NOT_FOUND
                        };
                    }
                }
                else {
                    return {
                        state: states.ExecutorResponseState.ERROR,
                        errorType: states.ExecutorErrorType.COMMAND_NOT_FOUND,
                        response: Object.keys(actualCommand.subCommands)
                    };
                }
            }
            return {
                state: states.ExecutorResponseState.SUCCESS,
                response: actualCommand.command
            };
        };
        CommandExecutorImpl.prototype.parse = function (commandString) {
            if (!commandString) {
                return [];
            }
            return commandParser.parse(commandString.trim());
        };
        CommandExecutorImpl.prototype.getCommandParts = function (parseResults) {
            if (!parseResults || parseResults.length === 0) {
                return null;
            }
            for (var _i = 0; _i < parseResults.length; _i++) {
                var result = parseResults[_i];
                if (result.type === 'COMMAND_PARAM') {
                    return result.values;
                }
            }
            return null;
        };
        CommandExecutorImpl.prototype.prepareCommands = function (commands) {
            if (!commands) {
                return;
            }
            var self = this;
            var commandMap = {};
            commands.forEach(function (command) {
                commandMap[command.name] = {
                    command: command
                };
                if (command.subCommands) {
                    commandMap[command.name].subCommands = self.prepareCommands(command.subCommands);
                }
            });
            return commandMap;
        };
        return CommandExecutorImpl;
    })();
    CommandJS.CommandExecutorImpl = CommandExecutorImpl;
    module.exports = CommandExecutorImpl;
})(CommandJS || (CommandJS = {}));

},{"./command-parser":2,"./states":4}],2:[function(_dereq_,module,exports){
module.exports = (function() {
  /*
   * Generated by PEG.js 0.8.0.
   *
   * http://pegjs.majda.cz/
   */

  function peg$subclass(child, parent) {
    function ctor() { this.constructor = child; }
    ctor.prototype = parent.prototype;
    child.prototype = new ctor();
  }

  function SyntaxError(message, expected, found, offset, line, column) {
    this.message  = message;
    this.expected = expected;
    this.found    = found;
    this.offset   = offset;
    this.line     = line;
    this.column   = column;

    this.name     = "SyntaxError";
  }

  peg$subclass(SyntaxError, Error);

  function parse(input) {
    var options = arguments.length > 1 ? arguments[1] : {},

        peg$FAILED = {},

        peg$startRuleFunctions = { start: peg$parsestart },
        peg$startRuleFunction  = peg$parsestart,

        peg$c0 = [],
        peg$c1 = peg$FAILED,
        peg$c2 = " ",
        peg$c3 = { type: "literal", value: " ", description: "\" \"" },
        peg$c4 = function(c) {return c;},
        peg$c5 = function(c, c1) {
            if(c1) {
              return toCommand([c].concat(c1))
            }
            else {
              return toCommand([c])
            }
          },
        peg$c6 = /^[^" "]/,
        peg$c7 = { type: "class", value: "[^\" \"]", description: "[^\" \"]" },
        peg$c8 = function(c) {return c.join("")},

        peg$currPos          = 0,
        peg$reportedPos      = 0,
        peg$cachedPos        = 0,
        peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
        peg$maxFailPos       = 0,
        peg$maxFailExpected  = [],
        peg$silentFails      = 0,

        peg$result;

    if ("startRule" in options) {
      if (!(options.startRule in peg$startRuleFunctions)) {
        throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
      }

      peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
    }

    function text() {
      return input.substring(peg$reportedPos, peg$currPos);
    }

    function offset() {
      return peg$reportedPos;
    }

    function line() {
      return peg$computePosDetails(peg$reportedPos).line;
    }

    function column() {
      return peg$computePosDetails(peg$reportedPos).column;
    }

    function expected(description) {
      throw peg$buildException(
        null,
        [{ type: "other", description: description }],
        peg$reportedPos
      );
    }

    function error(message) {
      throw peg$buildException(message, null, peg$reportedPos);
    }

    function peg$computePosDetails(pos) {
      function advance(details, startPos, endPos) {
        var p, ch;

        for (p = startPos; p < endPos; p++) {
          ch = input.charAt(p);
          if (ch === "\n") {
            if (!details.seenCR) { details.line++; }
            details.column = 1;
            details.seenCR = false;
          } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
            details.line++;
            details.column = 1;
            details.seenCR = true;
          } else {
            details.column++;
            details.seenCR = false;
          }
        }
      }

      if (peg$cachedPos !== pos) {
        if (peg$cachedPos > pos) {
          peg$cachedPos = 0;
          peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
        }
        advance(peg$cachedPosDetails, peg$cachedPos, pos);
        peg$cachedPos = pos;
      }

      return peg$cachedPosDetails;
    }

    function peg$fail(expected) {
      if (peg$currPos < peg$maxFailPos) { return; }

      if (peg$currPos > peg$maxFailPos) {
        peg$maxFailPos = peg$currPos;
        peg$maxFailExpected = [];
      }

      peg$maxFailExpected.push(expected);
    }

    function peg$buildException(message, expected, pos) {
      function cleanupExpected(expected) {
        var i = 1;

        expected.sort(function(a, b) {
          if (a.description < b.description) {
            return -1;
          } else if (a.description > b.description) {
            return 1;
          } else {
            return 0;
          }
        });

        while (i < expected.length) {
          if (expected[i - 1] === expected[i]) {
            expected.splice(i, 1);
          } else {
            i++;
          }
        }
      }

      function buildMessage(expected, found) {
        function stringEscape(s) {
          function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }

          return s
            .replace(/\\/g,   '\\\\')
            .replace(/"/g,    '\\"')
            .replace(/\x08/g, '\\b')
            .replace(/\t/g,   '\\t')
            .replace(/\n/g,   '\\n')
            .replace(/\f/g,   '\\f')
            .replace(/\r/g,   '\\r')
            .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
            .replace(/[\x10-\x1F\x80-\xFF]/g,    function(ch) { return '\\x'  + hex(ch); })
            .replace(/[\u0180-\u0FFF]/g,         function(ch) { return '\\u0' + hex(ch); })
            .replace(/[\u1080-\uFFFF]/g,         function(ch) { return '\\u'  + hex(ch); });
        }

        var expectedDescs = new Array(expected.length),
            expectedDesc, foundDesc, i;

        for (i = 0; i < expected.length; i++) {
          expectedDescs[i] = expected[i].description;
        }

        expectedDesc = expected.length > 1
          ? expectedDescs.slice(0, -1).join(", ")
              + " or "
              + expectedDescs[expected.length - 1]
          : expectedDescs[0];

        foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";

        return "Expected " + expectedDesc + " but " + foundDesc + " found.";
      }

      var posDetails = peg$computePosDetails(pos),
          found      = pos < input.length ? input.charAt(pos) : null;

      if (expected !== null) {
        cleanupExpected(expected);
      }

      return new SyntaxError(
        message !== null ? message : buildMessage(expected, found),
        expected,
        found,
        pos,
        posDetails.line,
        posDetails.column
      );
    }

    function peg$parsestart() {
      var s0, s1;

      s0 = [];
      s1 = peg$parsecommandsOrParams();
      if (s1 !== peg$FAILED) {
        while (s1 !== peg$FAILED) {
          s0.push(s1);
          s1 = peg$parsecommandsOrParams();
        }
      } else {
        s0 = peg$c1;
      }

      return s0;
    }

    function peg$parsecommandsOrParams() {
      var s0, s1, s2, s3, s4, s5;

      s0 = peg$currPos;
      s1 = peg$parsecommandOrParam();
      if (s1 !== peg$FAILED) {
        s2 = [];
        s3 = peg$currPos;
        s4 = [];
        if (input.charCodeAt(peg$currPos) === 32) {
          s5 = peg$c2;
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
          if (peg$silentFails === 0) { peg$fail(peg$c3); }
        }
        if (s5 !== peg$FAILED) {
          while (s5 !== peg$FAILED) {
            s4.push(s5);
            if (input.charCodeAt(peg$currPos) === 32) {
              s5 = peg$c2;
              peg$currPos++;
            } else {
              s5 = peg$FAILED;
              if (peg$silentFails === 0) { peg$fail(peg$c3); }
            }
          }
        } else {
          s4 = peg$c1;
        }
        if (s4 !== peg$FAILED) {
          s5 = peg$parsecommandOrParam();
          if (s5 !== peg$FAILED) {
            peg$reportedPos = s3;
            s4 = peg$c4(s5);
            s3 = s4;
          } else {
            peg$currPos = s3;
            s3 = peg$c1;
          }
        } else {
          peg$currPos = s3;
          s3 = peg$c1;
        }
        while (s3 !== peg$FAILED) {
          s2.push(s3);
          s3 = peg$currPos;
          s4 = [];
          if (input.charCodeAt(peg$currPos) === 32) {
            s5 = peg$c2;
            peg$currPos++;
          } else {
            s5 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c3); }
          }
          if (s5 !== peg$FAILED) {
            while (s5 !== peg$FAILED) {
              s4.push(s5);
              if (input.charCodeAt(peg$currPos) === 32) {
                s5 = peg$c2;
                peg$currPos++;
              } else {
                s5 = peg$FAILED;
                if (peg$silentFails === 0) { peg$fail(peg$c3); }
              }
            }
          } else {
            s4 = peg$c1;
          }
          if (s4 !== peg$FAILED) {
            s5 = peg$parsecommandOrParam();
            if (s5 !== peg$FAILED) {
              peg$reportedPos = s3;
              s4 = peg$c4(s5);
              s3 = s4;
            } else {
              peg$currPos = s3;
              s3 = peg$c1;
            }
          } else {
            peg$currPos = s3;
            s3 = peg$c1;
          }
        }
        if (s2 !== peg$FAILED) {
          peg$reportedPos = s0;
          s1 = peg$c5(s1, s2);
          s0 = s1;
        } else {
          peg$currPos = s0;
          s0 = peg$c1;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$c1;
      }

      return s0;
    }

    function peg$parsecommandOrParam() {
      var s0;

      s0 = peg$parsecharacters();

      return s0;
    }

    function peg$parsecharacters() {
      var s0, s1, s2;

      s0 = peg$currPos;
      s1 = [];
      if (peg$c6.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
        if (peg$silentFails === 0) { peg$fail(peg$c7); }
      }
      if (s2 !== peg$FAILED) {
        while (s2 !== peg$FAILED) {
          s1.push(s2);
          if (peg$c6.test(input.charAt(peg$currPos))) {
            s2 = input.charAt(peg$currPos);
            peg$currPos++;
          } else {
            s2 = peg$FAILED;
            if (peg$silentFails === 0) { peg$fail(peg$c7); }
          }
        }
      } else {
        s1 = peg$c1;
      }
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c8(s1);
      }
      s0 = s1;

      return s0;
    }

      function toCommand(c) {
        return {
          type: "COMMAND_PARAM",
          values: c
        };
      }

    peg$result = peg$startRuleFunction();

    if (peg$result !== peg$FAILED && peg$currPos === input.length) {
      return peg$result;
    } else {
      if (peg$result !== peg$FAILED && peg$currPos < input.length) {
        peg$fail({ type: "end", description: "end of input" });
      }

      throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
    }
  }

  return {
    SyntaxError: SyntaxError,
    parse:       parse
  };
})();
},{}],3:[function(_dereq_,module,exports){
var CommandJS;
(function (CommandJS) {
    "use strict";
    var CommandExecutor = _dereq_('./command-executor');
    var states = _dereq_('./states');
    module.exports = {
        ExecutorResponseState: states.ExecutorResponseState,
        ExecutorErrorType: states.ExecutorErrorType,
        executor: function (commands) {
            return new CommandExecutor(commands);
        }
    };
})(CommandJS || (CommandJS = {}));

},{"./command-executor":1,"./states":4}],4:[function(_dereq_,module,exports){
var CommandJS;
(function (CommandJS) {
    (function (ExecutorResponseState) {
        ExecutorResponseState[ExecutorResponseState["SUCCESS"] = 0] = "SUCCESS";
        ExecutorResponseState[ExecutorResponseState["ERROR"] = 1] = "ERROR";
    })(CommandJS.ExecutorResponseState || (CommandJS.ExecutorResponseState = {}));
    var ExecutorResponseState = CommandJS.ExecutorResponseState;
    (function (ExecutorErrorType) {
        ExecutorErrorType[ExecutorErrorType["COMMAND_NOT_FOUND"] = 0] = "COMMAND_NOT_FOUND";
        ExecutorErrorType[ExecutorErrorType["PARSER_ERROR"] = 1] = "PARSER_ERROR";
        ExecutorErrorType[ExecutorErrorType["COMMAND_EXECUTION_ERROR"] = 2] = "COMMAND_EXECUTION_ERROR";
    })(CommandJS.ExecutorErrorType || (CommandJS.ExecutorErrorType = {}));
    var ExecutorErrorType = CommandJS.ExecutorErrorType;
    module.exports = {
        ExecutorResponseState: ExecutorResponseState,
        ExecutorErrorType: ExecutorErrorType
    };
})(CommandJS || (CommandJS = {}));

},{}]},{},[3])
(3)
});


text:
#include "tensorflow/compiler/xla/service/cpu/cpu_parallelization_preparation.h"

#include "tensorflow/compiler/xla/map_util.h"
#include "tensorflow/compiler/xla/service/cpu/ir_emission_utils.h"
#include "tensorflow/compiler/xla/service/cpu/shape_partition.h"
#include "tensorflow/compiler/xla/service/hlo_computation.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/service/logical_buffer.h"
#include "tensorflow/compiler/xla/service/tuple_points_to_analysis.h"
#include "tensorflow/compiler/xla/types.h"
#include "tensorflow/compiler/xla/util.h"
#include "tensorflow/core/lib/strings/strcat.h"

namespace xla {
namespace cpu {

StatusOr<bool> ParallelizationPreparation::Run(HloModule* module) {
  XLA_VLOG_LINES(2, "ParallelizationPreparation ENTRY");
  XLA_VLOG_LINES(2, module->ToString());

  bool changed = false;
  TF_ASSIGN_OR_RETURN(changed, RunParallelTaskAssignment(module));

  HloComputation* entry_computation = module->entry_computation();
  std::unordered_set<HloInstruction*> outlined;
  std::vector<HloInstruction*> instructions_to_outline;
  for (HloInstruction* instruction :
       entry_computation->MakeInstructionPostOrder()) {
    // If the instruction has been outlined, it no longer exists and we must not
    // dereference it.
    if (outlined.count(instruction) > 0) {
      continue;
    }

    // Skip parameters and constants, there is nothing to parallelize.
    if (instruction->opcode() == HloOpcode::kParameter ||
        instruction->opcode() == HloOpcode::kConstant) {
      continue;
    }

    // Outline 'instruction' in isolation if it was assigned parallel tasks.
    if (OutlineParallelizableInstruction(instruction)) {
      outlined.insert(instruction);
      changed = true;
      continue;
    }

    instructions_to_outline.clear();
    HloInstruction* outline_candidate = instruction;
    instructions_to_outline.push_back(outline_candidate);
    bool all_bitcasts = outline_candidate->opcode() == HloOpcode::kBitcast;

    // Outline sole users with the current instruction.
    while (CanOutlineWithUser(outline_candidate)) {
      HloInstruction* prior_candidate = outline_candidate;
      outline_candidate = *outline_candidate->users().begin();
      all_bitcasts &= outline_candidate->opcode() == HloOpcode::kBitcast;
      if (std::any_of(outline_candidate->operands().begin(),
                      outline_candidate->operands().end(),
                      [&](const HloInstruction* operand) {
                        // Do not consider any candidates which have operands
                        // other than the prior candidate, constants or
                        // parameters. Otherwise, we'd increase the fan-in which
                        // would reduce parallelism.
                        return operand->opcode() != HloOpcode::kParameter &&
                               operand->opcode() != HloOpcode::kConstant &&
                               operand != prior_candidate;
                      })) {
        break;
      }
      instructions_to_outline.push_back(outline_candidate);
    }
    // If all instructions in the outline candidates are a bitcast, then create
    // a copy at the head of the bitcasts and include it in the outlined
    // instructions. The underlying problem is that a computation which forwards
    // a parameter buffer to the output is not properly handled by the backends
    // or analysis.
    //
    // This would be better handled by being smarter about choosing outline
    // candidates in the first place.
    if (all_bitcasts) {
      // 'head' is the first instruction in the chain of bitcasts.
      HloInstruction* head = instructions_to_outline[0];
      HloInstruction* head_operand = head->mutable_operand(0);
      HloInstruction* copy =
          entry_computation->AddInstruction(HloInstruction::CreateUnary(
              head_operand->shape(), HloOpcode::kCopy, head_operand));
      TF_RETURN_IF_ERROR(head->ReplaceOperandWith(0, copy));
      instructions_to_outline.insert(instructions_to_outline.begin(), copy);
    }

    outlined.insert(instructions_to_outline.begin(),
                    instructions_to_outline.end());

    // Optimization to avoid replacing a single existing kCall with another
    // kCall that just calls the first one.
    if (instructions_to_outline.size() == 1 &&
        instructions_to_outline[0]->opcode() == HloOpcode::kCall) {
      continue;
    }

    module->OutlineExpressionFromComputation(
        instructions_to_outline,
        tensorflow::strings::StrCat("pp_", instruction->name()),
        entry_computation);
    changed = true;
  }

  TF_ASSIGN_OR_RETURN(auto points_to_analysis,
                      TuplePointsToAnalysis::Run(module));
  for (auto& computation : module->computations()) {
    if (computation->IsFusionComputation()) {
      continue;
    }
    HloInstruction* root = computation->root_instruction();
    // Copy root instruction if it does not define its own top-level buffer.
    // TODO(b/32885001) Remove these copies (at least for the unambiguous case).
    // TODO(b/32885001) Perform shallow copy if root value is a tuple.
    if (!points_to_analysis->InstructionDefinesBufferAtIndex(root,
                                                             /*index=*/{})) {
      HloInstruction* copy = computation->AddInstruction(
          HloInstruction::CreateUnary(root->shape(), HloOpcode::kCopy, root));
      computation->set_root_instruction(copy);
      changed = true;
    }
  }

  XLA_VLOG_LINES(2, "ParallelizationPreparation EXIT");
  XLA_VLOG_LINES(2, module->ToString());
  return changed;
}

StatusOr<bool> ParallelizationPreparation::RunParallelTaskAssignment(
    HloModule* module) {
  VLOG(1) << "RunParallelTaskAssignment max_parallelism_: " << max_parallelism_;
  bool changed = false;
  // Run cost analysis on entry computation.
  HloCostAnalysis cost_analysis(shape_size_);
  HloComputation* computation = module->entry_computation();
  Status cost_status = computation->root_instruction()->Accept(&cost_analysis);
  for (auto& instruction : computation->instructions()) {
    // Currently, we do not assign parallel tasks to instructions with at least
    // one of the following properties:
    // *) Internal threading (library calls to kConv, kDot, and kCustomCall).
    // *) Emit custom loops (kSelectAndScatter, FusionKind::kTransposeDot).
    // *) Tuple-shaped.
    // TODO(b/27458679) Parallelize instructions which are skipped here.
    if (instruction->opcode() == HloOpcode::kParameter ||
        instruction->opcode() == HloOpcode::kConstant ||
        instruction->opcode() == HloOpcode::kCall ||
        instruction->opcode() == HloOpcode::kCustomCall ||
        instruction->opcode() == HloOpcode::kSelectAndScatter ||
        (instruction->opcode() == HloOpcode::kConvolution &&
         PotentiallyImplementedAsEigenConvolution(*instruction)) ||
        PotentiallyImplementedAsEigenDot(*instruction) ||
        (instruction->opcode() == HloOpcode::kFusion &&
         instruction->fusion_kind() != HloInstruction::FusionKind::kLoop) ||
        ShapeUtil::IsTuple(instruction->shape())) {
      continue;
    }

    // Calculate target parallel task count in [1, max_parallelism_].
    const int64 target_parallel_task_count = GetTargetParallelTaskCount(
        cost_status.ok() ? &cost_analysis : nullptr, instruction.get());
    if (target_parallel_task_count == 1) {
      continue;
    }

    // Assign feasible dimension partitions (based on actual dimension sizes).
    auto dim_partition_counts = ShapePartitionAssigner(instruction->shape())
                                    .Run(target_parallel_task_count);
    const int64 total_partition_count =
        ShapePartitionAssigner::GetTotalPartitionCount(dim_partition_counts);
    if (total_partition_count <= 1) {
      // Feasible partition calculation resulting in no partitioning, so skip.
      continue;
    }
    VLOG(2) << "Assigning parallel task count: " << total_partition_count
            << " to instruction: " << instruction->name();
    // Map 'instruction' to assigned dimension partitioning.
    instruction->set_outer_dimension_partitions(dim_partition_counts);
  }

  return changed;
}

int64 ParallelizationPreparation::GetTargetParallelTaskCount(
    const HloCostAnalysis* cost_analysis, HloInstruction* instruction) {
  // Default to a simple cost model based on hlo size and typical L2 cache size.
  // Note that 'cost_analysis' can be 'nullptr' if HloCostAnalysis returns an
  // error status (likely because HLOs like CustomCall are not yet implemented
  // in the HloCostAnalysis).
  int64 instruction_cost = shape_size_(instruction->shape());
  int64 min_cost_per_thread = 256LL << 10;  // 256KB L2 Cache size.
  if (cost_analysis != nullptr) {
    // Calculate the instruction cost in cycles.
    // TODO(29630486) Improve on this linear cost model.
    // Consider making 'min_cost_per_thread' be a function of the target
    // bandwidth limit for instructions with low arithmetic complexity.
    instruction_cost = 1 * cost_analysis->flop_count(*instruction) +
                       2 * cost_analysis->transcendental_count(*instruction) +
                       10 * cost_analysis->bytes_accessed(*instruction);
    // Minimum per-thread cost is 100us of work on a 2GHz core.
    min_cost_per_thread = 100000;
  }
  // Return target parallel task count in [1, max_parallelism_].
  return std::min(max_parallelism_,
                  std::max(1LL, instruction_cost / min_cost_per_thread));
}

bool ParallelizationPreparation::OutlineParallelizableInstruction(
    HloInstruction* instruction) {
  if (instruction->outer_dimension_partitions().empty()) {
    return false;
  }
  // Store dimension partition counts before outlining (which clones
  // 'instruction').
  std::vector<int64> dim_partition_counts =
      instruction->outer_dimension_partitions();
  // Outline 'instruction' in its own sub-computation.
  HloModule* module = instruction->parent()->parent();
  auto* call = module->OutlineExpressionFromComputation(
      {instruction}, tensorflow::strings::StrCat("pp_", instruction->name()),
      module->entry_computation());
  // Map previously assigned 'dim_partition_counts' to cloned root instruction.
  VLOG(1) << "Outlining parallelizable"
          << " caller: " << call->name()
          << " callee: " << call->to_apply()->root_instruction()->name();
  call->to_apply()->root_instruction()->set_outer_dimension_partitions(
      dim_partition_counts);
  return true;
}

bool ParallelizationPreparation::CanOutlineWithUser(
    HloInstruction* instruction) {
  if (instruction->users().size() != 1) {
    // Do not outline 'instruction' with multiple users.
    return false;
  }
  if (AssignedParallelTasks(instruction) ||
      AssignedParallelTasks(*instruction->users().begin())) {
    // Do not outline if 'instruction' (or user) were assigned parallel tasks.
    return false;
  }
  return true;
}

bool ParallelizationPreparation::AssignedParallelTasks(
    HloInstruction* instruction) {
  return !instruction->outer_dimension_partitions().empty() ||
         (instruction->opcode() == HloOpcode::kCall &&
          !instruction->to_apply()
               ->root_instruction()
               ->outer_dimension_partitions()
               .empty());
}

}  // namespace cpu
}  // namespace xla

redpajama_set_name: RedPajamaGithub


text:
package imj3.draft;

import static imj3.core.IMJCoreTools.*;
import static imj3.tools.IMJTools.*;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static multij.swing.SwingTools.horizontalBox;
import static multij.swing.SwingTools.horizontalSplit;
import static multij.swing.SwingTools.scrollable;
import static multij.swing.SwingTools.show;
import static multij.tools.Tools.*;
import static multij.xml.XMLTools.getNumber;

import imj3.core.Channels;
import imj3.core.IMJCoreTools;
import imj3.core.IMJCoreTools.Reference;
import imj3.core.Image2D;
import imj3.core.Image2D.Pixel2DProcessor;
import imj3.tools.AwtImage2D;
import imj3.tools.IMJTools;
import imj3.tools.IMJTools.ComponentComembership;
import imj3.tools.Image2DComponent;
import imj3.tools.Image2DComponent.Overlay;
import imj3.tools.Image2DComponent.TileOverlay;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.IOException;
import java.io.Serializable;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.OptionalInt;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import multij.primitivelists.FloatList;
import multij.swing.SwingTools;
import multij.tools.Canvas;
import multij.tools.CommandLineArgumentsParser;
import multij.tools.IllegalInstantiationException;

import org.w3c.dom.Element;

/**
 * @author codistmonk (creation 2016-06-03)
 */
public final class QuickSeg2 {

	private QuickSeg2() {
		throw new IllegalInstantiationException();
	}

	/**
	 * @param commandLineArguments
	 * <br>Must not be null
	 */
	public static final void main(final String... commandLineArguments) {
		final CommandLineArgumentsParser arguments = new CommandLineArgumentsParser(commandLineArguments);
		final String imagePath = arguments.get("image", "");

		if (!imagePath.isEmpty()) {
			debugPrint("image:", imagePath);

			final int q = arguments.get("q", 5)[0];
			final int s = arguments.get("s", 16)[0];

			debugPrint("q:", q, "s:", s);

			final Image2D image = IMJTools.read(imagePath);
			final String outputPath = baseName(imagePath) + "_segments.zip";

			debugPrint("output:", outputPath);

			segmentFull(image, q, s, outputPath, Monitor.DEFAULT);

			return;
		}

		SwingTools.useSystemLookAndFeel();

		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public final void run() {
				final Context context = new Context();
				final JPanel mainPanel = newMainPanel(context);
				final Window mainFrame = show(mainPanel, "Image");

				mainFrame.addWindowListener(new WindowAdapter() {

					@Override
					public final void windowClosing(final WindowEvent event) {
						context.destroy();
					}

				});
			}

		});
	}

	public static final void segmentFull(final Image2D image, final int q, final int s, final String outputPath, final Monitor monitor) {
		final int w0 = image.getWidth();
		final int h0 = image.getHeight();
		final String tileFormat = "png";

		createZipImage(outputPath, image.getWidth(), image.getHeight(), image.getOptimalTileWidth(), image.getOptimalTileHeight(), tileFormat, (Double) image.getMetadata().get("micronsPerPixel"), new TileGenerator() {

			private ZipOutputStream output;

			private String type;

			private Image2D im;

			@Override
			public final ZipOutputStream getOutput() {
				return this.output;
			}

			@Override
			public final void setOutput(final ZipOutputStream output) {
				this.output = output;
			}

			@Override
			public final void setElement(final Element imageElement) {
				this.type = imageElement.getAttribute("type");
				final int w = getNumber(imageElement, "@width").intValue();
				final int h = getNumber(imageElement, "@height").intValue();
				this.im = image.getScaledImage(max((double) w / w0, (double) h / h0));
			}

			@Override
			public final boolean pixel(final int tileX, final int tileY) {
				final BufferedImage segments = segment(this.im.getTile(tileX, tileY), q, s, 0xFF000000, monitor);

				if (tileX == 0) {
					debugPrint(this.im.getId(), this.type, tileX, tileY);
				}

				try {
					this.output.putNextEntry(new ZipEntry("tiles/tile_" + this.type + "_y" + tileY + "_x" + tileX + "." + tileFormat));
					ImageIO.write(segments, tileFormat, this.output);
					this.output.closeEntry();
				} catch (final IOException exception) {
					throw new UncheckedIOException(exception);
				}

				return segments != null;
			}

			private static final long serialVersionUID = -349954077441100567L;

		});
	}

	public static final BufferedImage segment(final Image2D image, final int q, final int s, final int id0, final Monitor monitor) {
		final int w = image.getWidth();
		final int h = image.getHeight();
		final BufferedImage transformedMiddle = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
		final BufferedImage segments = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
		final Channels channels = image.getChannels();
		final int qMask = ((~0) << q) & 0xFF;

		for (int y = 0; y < h; ++y) {
			if (monitor.isCancelRequested()) {
				return null;
			}

			for (int x = 0; x < w; ++x) {
				final long value = image.getPixelValue(x, y);
				final int r = (int) channels.getChannelValue(value, 0);
				final int g = (int) channels.getChannelValue(value, 1);
				final int b = (int) channels.getChannelValue(value, 2);
				long newMiddleValue = channels.setChannelValue(0L, 0, qMask & r);
				newMiddleValue = channels.setChannelValue(newMiddleValue, 1, qMask & g);
				newMiddleValue = channels.setChannelValue(newMiddleValue, 2, qMask & b);

				transformedMiddle.setRGB(x, y, (int) newMiddleValue);
			}
		}

		final int[] id = { id0 };

		forEachTile(w, h, s, s, new Pixel2DProcessor() {

			@Override
			public final boolean pixel(final int tileX, final int tileY) {
				if (monitor.isCancelRequested()) {
					id[0] = -1;
					return false;
				}

				final int tw = min(s, w - tileX);
				final int th = min(s, h - tileY);

				forEachPixelInEachComponent4(image, new Rectangle(tileX, tileY, tw, th), new ComponentComembership() {

					@Override
					public final boolean test(final Image2D image, final long pixel, final long otherPixel) {
						final int x = image.getX(pixel);
						final int y = image.getY(pixel);
						final int otherX = image.getX(otherPixel);
						final int otherY = image.getY(otherPixel);

						return transformedMiddle.getRGB(x, y) == transformedMiddle.getRGB(otherX, otherY);
					}

					private static final long serialVersionUID = 6632151904983956288L;

				}, new Pixel2DProcessor() {

					@Override
					public final boolean pixel(final int x, final int y) {
						segments.setRGB(x, y, id[0]);

						return true;
					}

					@Override
					public final void endOfPatch() {
						++id[0];
					}

					private static final long serialVersionUID = -6435721813416466409L;

				});

				return true;
			}

			private static final long serialVersionUID = 13671048674063813L;

		});

		return id[0] == -1 ? null : segments;
	}

	public static final Image2D outline(final BufferedImage segments, final Monitor monitor) {
		final int w = segments.getWidth();
		final int h = segments.getHeight();
		final AwtImage2D result = new AwtImage2D("", w, h);

		for (int y = 0; y < h; ++y) {
			if (monitor.isCancelRequested()) {
				return null;
			}

			for (int x = 0; x < w; ++x) {
				final long center = segments.getRGB(x, y);
				boolean mark = false;

				if (0 < y) {
					mark = mark || center != segments.getRGB(x, y - 1);
				}

				if (0 < x) {
					mark = mark || center != segments.getRGB(x - 1, y);
				}

				mark = mark || x == 0 || x == w - 1 || y == 0 || y == h - 1;

				if (mark) {
					result.setPixelValue(x, y, 0xFF00FF00L);
				}
			}
		}

		return result;
	}

	public static final JPanel newMainPanel(final Context context) {
		final JPanel result = new JPanel(new BorderLayout());

		context.setMainPanel(result);
		context.setqField(new JTextField("6"));
		context.setsField(new JTextField("32"));
		context.setFineCheckBox(new JCheckBox("Fine view"));

		final JButton convolutionalHistogramButton = new JButton("ConvHisto...");

		final Box optionsBox = horizontalBox(
				new JLabel("Q:"), context.getqField(),
				new JLabel("S:"), context.getsField(),
				context.getFineCheckBox(),
				convolutionalHistogramButton);
		context.setImageComponent(new Image2DComponent(new AwtImage2D("", 256, 256)).setDropImageEnabled(true));

		result.add(optionsBox, BorderLayout.NORTH);
		result.add(context.getImageComponent(), BorderLayout.CENTER);

		final ActionListener fieldActionListener = new ActionListener() {

			@Override
			public final void actionPerformed(final ActionEvent event) {
				context.clearKeys();
				context.getHash().incrementAndGet();
				context.getImageComponent().repaint();
			}

		};

		context.getqField().addActionListener(fieldActionListener);
		context.getsField().addActionListener(fieldActionListener);
		context.getFineCheckBox().addActionListener(fieldActionListener);

		convolutionalHistogramButton.addActionListener(new ActionListener() {

			@Override
			public final void actionPerformed(final ActionEvent event) {
				final ConvolutionalHistogramPanel convhistoPanel = new ConvolutionalHistogramPanel(context);
				final Window window = show(convhistoPanel, "Convolutional histogram");

				window.addWindowListener(new WindowAdapter() {

					@Override
					public final void windowClosing(WindowEvent event) {
						context.getRepaintListeners().remove(convhistoPanel);
					}

				});
			}

		});

		context.getImageComponent().setTileOverlay(new QuickSegTileOverlay(context));
		context.getImageComponent().setOverlay(new QuickSegOverlay(context));

		return result;
	}

	/**
	 * @author codistmonk (creation 2016-06-06)
	 */
	public static final class ConvolutionalHistogramPanel extends JPanel implements Context.RepaintListener {

		private final Context context;

		private final Canvas canvas;

		private final JTextArea kernelEditor;

		private final JComponent histoView;

		private final int[] counts;

		private ConvolveOp op;

		public ConvolutionalHistogramPanel(final Context context) {
			super(new BorderLayout());
			this.context = context;
			this.canvas = new Canvas();
			this.kernelEditor = new JTextArea("1");
			this.histoView = new JComponent() {

				{
					this.setPreferredSize(new Dimension(256, 256));
					this.setMinimumSize(new Dimension(256, 256));
				}

				@Override
				public final void paintComponent(final Graphics graphics) {
					graphics.setColor(Color.WHITE);
					graphics.fillRect(0, 0, 256, 256);

					final OptionalInt s = Arrays.stream(getCounts()).max();

					if (s.isPresent() && 0 < s.getAsInt()) {
						graphics.setColor(Color.BLACK);

						for (int i = 0; i < 256; ++i) {
							graphics.drawLine(i, 255, i, 255 - 255 * getCounts()[i] / s.getAsInt());
						}
					}
				}

				private static final long serialVersionUID = 619396278275341879L;

			};
			this.counts = new int[256];
			this.op = new ConvolveOp(new Kernel(1, 1, new float[] { 1F }));

			context.getRepaintListeners().add(this);

			this.add(horizontalSplit(scrollable(this.kernelEditor), scrollable(this.histoView)), BorderLayout.CENTER);

			this.kernelEditor.addKeyListener(new KeyAdapter() {

				@Override
				public final void keyPressed(final KeyEvent event) {
					if (event.isControlDown() && event.getKeyCode() == KeyEvent.VK_ENTER) {
						final FloatList data = new FloatList();
						int rowCount = 0;

						try (final Scanner scanner = new Scanner(ConvolutionalHistogramPanel.this.getKernelEditor().getText())) {
							scanner.useLocale(Locale.ENGLISH);

							while (scanner.hasNext()) {
								try (final Scanner lineScanner = new Scanner(scanner.nextLine())) {
									lineScanner.useLocale(Locale.ENGLISH);

									while (lineScanner.hasNext()) {
										data.add(lineScanner.nextFloat());
									}

									++rowCount;
								}
							}
						} catch (final Exception exception) {
							exception.printStackTrace();
							return;
						}

						ConvolutionalHistogramPanel.this.setOp(new Kernel(data.size() / rowCount, rowCount, data.toArray()));
						repainted();
					}
				}

			});
		}

		@Override
		public final void repainted() {
			final BufferedImage source = this.context.getImageComponent().getCanvasImage();
			final int w = source.getWidth();
			final int h = source.getHeight();
			this.canvas.setFormat(w, h, source.getType());
			this.op.filter(source, this.canvas.getImage());

			Arrays.fill(this.counts, 0);

			for (int y = 0; y < h; ++y) {
				for (int x = 0; x < w; ++x) {
					final Color c = new Color(this.canvas.getImage().getRGB(x, y));

					++this.counts[(c.getRed() + c.getGreen() + c.getBlue()) / 3];
				}
			}

			this.repaint();
		}

		final JTextArea getKernelEditor() {
			return this.kernelEditor;
		}

		final int[] getCounts() {
			return this.counts;
		}

		final ConvolveOp getOp() {
			return this.op;
		}

		final void setOp(final Kernel kernel) {
			this.setOp(new ConvolveOp(kernel));
		}

		final void setOp(final ConvolveOp op) {
			this.op = op;
		}

		private static final long serialVersionUID = -5126774744460467675L;

	}

	/**
	 * @author codistmonk (creation 2016-06-06)
	 */
	public static final class QuickSegOverlay implements Overlay {

		private final Image2DComponent imageComponent;

		private final JCheckBox fineCheckBox;

		private final Canvas canvas;

		public QuickSegOverlay(final Context context) {
			this.imageComponent = context.getImageComponent();
			this.fineCheckBox = context.getFineCheckBox();
			this.canvas = new Canvas();
		}

		@Override
		public final void update(final Graphics2D graphics, final Rectangle region) {
			if (region.isEmpty() || !this.fineCheckBox.isSelected()) {
				return;
			}

			this.canvas.setFormat(region.width, region.height).clear(new Color(0, true));

			final Point2D p0 = new Point2D.Double(0.0, 0.0);
			final Point2D p1 = new Point2D.Double(1.0, 1.0);

			try {
				this.imageComponent.getView().inverseTransform(p0, p0);
				this.imageComponent.getView().inverseTransform(p1, p1);

				final double dx = p1.getX() - p0.getX();
				final double dy = p1.getY() - p0.getY();
				final int w = region.width;
				final int h = region.height;
				final Image2D image = this.imageComponent.getImage();
				final double scale = image.getScale();

				for (int y = 0; y < h; ++y) {
					for (int x = 0; x < w; ++x) {
						final int xIm = (int) ((p0.getX() + x * dx) * scale);
						final int yIm = (int) ((p0.getY() + y * dy) * scale);

						if (0 <= xIm && xIm < image.getWidth() && 0 <= yIm && yIm < image.getHeight()) {
							final int tileX = image.getTileXContaining(xIm);
							final int tileY = image.getTileYContaining(yIm);
							final String key = image.getTileKey(tileX, tileY) + "_segments";
							final Reference<BufferedImage> segments = getCached(key);

							if (segments != null && segments.hasObject()) {
								final int centerId = segments.getObject().getRGB(xIm - tileX, yIm - tileY);
								final int north = (int) ((p0.getY() + (y - 1) * dy) * scale);
								final int west = (int) ((p0.getX() + (x - 1) * dx) * scale);

								boolean mark = false;

								if (0 <= north && north < yIm) {
									final int northTileY = image.getTileYContaining(north);
									final String northKey = image.getTileKey(tileX, northTileY) + "_segments";
									final Reference<BufferedImage> northSegments = getCached(northKey);

									if (northSegments != null && northSegments.hasObject()) {
										mark = mark || centerId != northSegments.getObject().getRGB(xIm - tileX, north - northTileY);
									}
								}

								if (0 <= west && west < xIm) {
									final int westTileX = image.getTileXContaining(west);
									final String westKey = image.getTileKey(westTileX, tileY) + "_segments";
									final Reference<BufferedImage> westSegments = getCached(westKey);

									if (westSegments != null && westSegments.hasObject()) {
										mark = mark || centerId != westSegments.getObject().getRGB(west - westTileX, yIm - tileY);
									}
								}

								if (mark) {
									this.canvas.getImage().setRGB(x, y, 0xFF00FF00);
								}
							}
						}
					}
				}

				graphics.drawImage(this.canvas.getImage(), 0, 0, null);
			} catch (final NoninvertibleTransformException exception) {
				exception.printStackTrace();
			}
		}

		private static final long serialVersionUID = -6245612608729813604L;
	}

	/**
	 * @author codistmonk (creation 2016-06-06)
	 */
	public static abstract interface Monitor extends Serializable {

		public abstract boolean isCancelRequested();

		public static final Monitor DEFAULT = () -> false;

	}

	/**
	 * @author codistmonk (creation 2016-06-06)
	 */
	public static final class QuickSegTileOverlay implements TileOverlay {

		private final Context context;

		private final JTextField qField;

		private final JTextField sField;

		private final JCheckBox fineCheckBox;

		private final Image2DComponent imageComponent;

		public QuickSegTileOverlay(final Context context) {
			this.context = context;
			this.qField = context.getqField();
			this.sField = context.getsField();
			this.fineCheckBox = context.getFineCheckBox();
			this.imageComponent = context.getImageComponent();
		}

		@Override
		public final int hashCode() {
			return this.context.getHash().get();
		}

		@Override
		public final void update(final Graphics2D graphics, final Point tileXY, final Rectangle region) {
			final Image2D image = this.imageComponent.getImage();
			final String key = image.getTileKey(tileXY.x, tileXY.y) + "_outlines";
			final Reference<Image2D> cached = getCached(key);

			if (cached == null) {
//				graphics.setColor(Color.RED);
//				graphics.draw(region);

				if (this.context.getKeys().add(key)) {
					this.context.getExecutor().submit(new Runnable() {

						@Override
						public final void run() {
							cache(key, new Supplier<Image2D>() {

								@Override
								public final Image2D get() {
									final Monitor monitor = QuickSegTileOverlay.this.context.newKeyMonitor(key);
									final int q = Integer.decode(QuickSegTileOverlay.this.qField.getText());
									final int s = Integer.decode(QuickSegTileOverlay.this.sField.getText());
									final Image2D tile = image.getTile(tileXY.x, tileXY.y);
									final BufferedImage segments = segment(tile, q, s, 0, monitor);

									if (segments == null) {
										return null;
									}

									cache(image.getTileKey(tileXY.x, tileXY.y) + "_segments", () -> segments, true);

									if (QuickSegTileOverlay.this.fineCheckBox.isSelected() || max(tile.getWidth(), tile.getHeight()) < s) {
										return null;
									}

									return outline(segments, monitor);
								}

							});

							QuickSegTileOverlay.this.context.getHash().incrementAndGet();
							QuickSegTileOverlay.this.imageComponent.repaint();
						}

					});
				}
			} else if (cached.hasObject()) {
				graphics.drawImage((Image) cached.getObject().toAwt(), region.x, region.y, region.width, region.height, null);
			} else if (!this.fineCheckBox.isSelected()) {
//				graphics.setColor(Color.RED);
//				graphics.draw(region);
			}

			this.context.getRepaintListeners().forEach(Context.RepaintListener::repainted);
		}

		private static final long serialVersionUID = -4573576871706331668L;

	}

	/**
	 * @author codistmonk (creation 2016-06-06)
	 */
	public static final class Context implements Serializable {

		private final ExecutorService executor = Executors.newFixedThreadPool(4);

		private final Collection<String> keys = new HashSet<>();

		private final AtomicInteger hash = new AtomicInteger(1);

		private final Collection<RepaintListener> repaintListeners = new ArrayList<>();

		private JPanel mainPanel;

		private JTextField qField;

		private JTextField sField;

		private JCheckBox fineCheckBox;

		private Image2DComponent imageComponent;

		public final ExecutorService getExecutor() {
			return this.executor;
		}

		public final Collection<String> getKeys() {
			return this.keys;
		}

		public final AtomicInteger getHash() {
			return this.hash;
		}

		public final Collection<RepaintListener> getRepaintListeners() {
			return this.repaintListeners;
		}

		public final JPanel getMainPanel() {
			return this.mainPanel;
		}

		public final void setMainPanel(final JPanel mainPanel) {
			this.mainPanel = mainPanel;
		}

		public final JTextField getqField() {
			return this.qField;
		}

		public final void setqField(final JTextField qField) {
			this.qField = qField;
		}

		public final JTextField getsField() {
			return this.sField;
		}

		public final void setsField(final JTextField sField) {
			this.sField = sField;
		}

		public final JCheckBox getFineCheckBox() {
			return this.fineCheckBox;
		}

		public final void setFineCheckBox(final JCheckBox fineCheckBox) {
			this.fineCheckBox = fineCheckBox;
		}

		public final Image2DComponent getImageComponent() {
			return this.imageComponent;
		}

		public final void setImageComponent(final Image2DComponent imageComponent) {
			this.imageComponent = imageComponent;
		}

		public final void clearKeys() {
			this.getKeys().forEach(IMJCoreTools::uncache);
			this.getKeys().clear();
		}

		public final Monitor newKeyMonitor(final String key) {
			return () -> !this.getKeys().contains(key);
		}

		public final void destroy() {
			this.getExecutor().shutdown();
			this.getKeys().clear();
		}

		private static final long serialVersionUID = -5610744496161785513L;

		/**
		 * @author codistmonk (creation 2016-06-06)
		 */
		public static abstract interface RepaintListener extends Serializable {

			public abstract void repainted();

		}

	}

}


text:
/**
 * Interface to get statistics from a text file. Used in the testing program.
 * @author CS121 Instructors
 */
package project3;

public interface TextStatisticsInterface
{
	/**
	 * @return the number of characters in the text file
	 */
	public int getCharCount();

	/**
	 * @return the number of words in the text file
	 */
	public int getWordCount();

	/**
	 * @return the number of lines in the text file
	 */
	public int getLineCount();

	/**
	 * @return the letterCount array with locations [0]..[25] for 'a' through 'z'
	 */
	public int[] getLetterCount();

	/**
	 * @return the wordLengthCount array with locations [0]..[23] with location [i]
	 * storing the number of words of length i in the text file. Location [0] is not used.
	 * Location [23] holds the count of words of length 23 and higher.
	 */
	public int[] getWordLengthCount();

	/**
	 * @return the average word length in the text file
	 */
	public double getAverageWordLength();
}