Elliptium http://tink.elliptium.net/ resoluto en-us Mon, 27 Feb 2017 00:00:00 +0900 http://tink.elliptium.net/2017/02/27/actual_translation_work.html http://tink.elliptium.net/2017/02/27/actual_translation_work.html <![CDATA[翻訳作業って何をするの?]]> 翻訳作業って何をするの?

前回 に引き続き Python ドキュメントの翻訳プロジェクトの話をします. 今回は翻訳プロジェクトが実際にはどんなふうに進められているかについて解説しましょう.

「翻訳作業」は形式的な見方をすれば, 英語で書かれた文章を日本語の文章に変換することです. CPython では, 英語の原文は Sphinx で作られていて CPython と一緒に GitHub レポジトリ で管理されています. では, これをフォークしてソースファイルを書き換えてビルドし, どこかのサーバーでホストすれば翻訳は完了でしょうか?

いいえ. 翻訳した時点では作業は完了したように思えるかもしれませんが, 原文はどんどん更新されていきます. その理由は CPython への文法の追加かもしれませんし, 新しい標準ライブラリの追加かもしれません. またドキュメントの誤りの訂正かもしれません. いずれにせよ訳文も原文の更新に追い付く必要があるでしょう. そのとき原文を直接訳文で置き換えてしまっていては, 原文の更新を管理するのが難しくなるでしょう.

gettext

そこで国際化 (internationalization, i18n) もしくは地域化 (localization, l10n) のツールを使うわけです.

続きを読む...

]]>
Mon, 27 Feb 2017 00:00:00 +0900
http://tink.elliptium.net/2017/02/23/now_started_translation_project_for_python_3_6_document.html http://tink.elliptium.net/2017/02/23/now_started_translation_project_for_python_3_6_document.html <![CDATA[Python 3.6 ドキュメント翻訳プロジェクト始動!!]]> Python 3.6 ドキュメント翻訳プロジェクト始動!!

Python 3.6 が 2016/12/23 にリリースされ, 日本でも リリースパーティー が開催されました.

Python は手厚いドキュメントがあることで有名 (?) で, そのドキュメントを日本語へ翻訳するプロジェクトも行われています. みなさんも Python について Web 検索したときにこのページを見たことがあると思います.

docs.python.jp

この日本語のドキュメントを作っているのが, その翻訳プロジェクトです.

翻訳プロジェクトでは, Python 2 系と Python 3 系の最新のドキュメントを翻訳対象としています. (過去のバージョンはプロジェクトの人手的に対象にできていません.)

本家の GitHub レポジトリの移行 (作り直し) が終わるのを待っていたのもあって, Python 3.6 がリリースから日が経ってしまいましたが, 準備を整え 2017/02/17 に翻訳プロジェクトを開始しました.

前バージョンから変わっていない文章は既に翻訳が適用されているので, 現在翻訳率は 87% です. 残りの未訳の部分もこれからドンドン翻訳していくのでお楽しみに.

Python 3.6 の新機能は色々あるのですが, 自分が興味のある「変数アノテーション」の部分を翻訳しようと思っています.

あ, それと翻訳に興味のある方, 協力してくださる方はいつでも大歓迎です. 普段 Python を使っている方, 翻訳そのものに興味のある方, 何かの形で OSS 活動に関わってみたい方などなどお待ちしてます!! 誤植報告もお気軽に. GitHub の issue でも, ハッシュタグ #pythondocja を付けて Twitter でつぶやくのでも構いません.

GitHub: https://github.com/python-doc-ja/python-doc-ja/

次の記事では, 翻訳作業って何をするの? という疑問に答える予定です.

それでは.

]]>
Thu, 23 Feb 2017 00:00:00 +0900
http://tink.elliptium.net/2016/11/05/gwjp2016_slides.html http://tink.elliptium.net/2016/11/05/gwjp2016_slides.html <![CDATA[Geek Women Japan 2016のスライド]]> Geek Women Japan 2016のスライド
イベントページ:http://geekwomenjapan.github.io/conference2016/index.html
]]>
Sat, 05 Nov 2016 00:00:00 +0900
http://tink.elliptium.net/2016/11/04/geek_women_japan_2016.html http://tink.elliptium.net/2016/11/04/geek_women_japan_2016.html <![CDATA[Geek Women Japan 2016へ行ってきました]]> Geek Women Japan 2016へ行ってきました
イベントページ:http://geekwomenjapan.github.io/conference2016/index.html

経緯

このイベントのことはTwitter経由で知り,「面白そう」という理由で参加しました. ちょうど自由に動ける祝日だったし, 久々の勉強会ということで気分転換に出掛けてきました.

忙しくなって勉強会に行かなくなったことや社内の環境の関係で, 普段は女性エンジニアと対面で話す機会は皆無です. 女性エンジニアがどんなことを考えたり思ったりするのかを知りたいな, なんてことを考えながら会場へ向かいました.

ちなみにGeek Women Japanという団体での「女性エンジニア」の定義は 「技術をたしなんでいる、自分は女性であると思っているすべての方」だそうです (http://geekwomenjapan.github.io/index.html#definition). この記事での「女性エンジニア」の定義もこれに倣うことにします.

参加したセッション

女性エンジニアとして何を考えているのかという話が聞けそうなセッションを聞いてきました.

  • opening・スポンサーLT
  • Keynote
  • ポスターセッション
  • 29歳の私が色々な人に聞いてみた『ちょうどいい働き方』 〜ところで、お仕事は好きですか?〜
  • 女性エンジニアの新しいキャリアパス~ホワイトハッカーという選択肢~
  • スポンサーLT・closing

続きを読む...

]]>
Fri, 04 Nov 2016 00:00:00 +0900
http://tink.elliptium.net/2016/08/28/hive_note_3.html http://tink.elliptium.net/2016/08/28/hive_note_3.html <![CDATA[Hive覚え書き・その3]]> Hive覚え書き・その3

where句に出てくるデフォルト・パーティションをどう処理しているかの調査中.

qlプロジェクトの調査

grep -nIR 'DEFAULTPARTITIONNAME' --include '*.java' ./ql/src/java/org/apache/hadoop/hive/ql/
./ql/src/java/org/apache/hadoop/hive/ql//exec/ColumnStatsTask.java:364:            this.conf.getVar(ConfVars.DEFAULTPARTITIONNAME) : partVal.toString());
./ql/src/java/org/apache/hadoop/hive/ql//exec/DDLTask.java:1105:        if (part.getName().equals(conf.getVar(HiveConf.ConfVars.DEFAULTPARTITIONNAME))) {
./ql/src/java/org/apache/hadoop/hive/ql//exec/TableScanOperator.java:258:    defaultPartitionName = HiveConf.getVar(hconf, HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql//metadata/Hive.java:2569:    String defaultPartitionName = HiveConf.getVar(conf, ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql//optimizer/ppr/PartitionPruner.java:476:    String defaultPartitionName = conf.getVar(HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql//parse/BaseSemanticAnalyzer.java:1474:    String defaultPartitionName = HiveConf.getVar(conf, HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql//parse/DDLSemanticAnalyzer.java:244:    reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.DEFAULTPARTITIONNAME));
./ql/src/java/org/apache/hadoop/hive/ql//parse/SemanticAnalyzer.java:6594:              conf.getVar(HiveConf.ConfVars.DEFAULTPARTITIONNAME),
./ql/src/java/org/apache/hadoop/hive/ql//stats/StatsUtils.java:438:                ci.getType().getTypeName(), conf.getVar(ConfVars.DEFAULTPARTITIONNAME)));

うーん, org.apache.hive.ql.parse パッケージあたりを探ればいいのかな?

org.apache.hive.ql.parse.BaseSemanticAnalyzer

/**
 * BaseSemanticAnalyzer.
 *
 */
public abstract class BaseSemanticAnalyzer {
  // ...
  private static boolean getPartExprNodeDesc(ASTNode astNode, HiveConf conf,
      Map<ASTNode, ExprNodeDesc> astExprNodeMap) throws SemanticException {

    if (astNode == null) {
      return true;
    } else if ((astNode.getChildren() == null) || (astNode.getChildren().size() == 0)) {
      return astNode.getType() != HiveParser.TOK_PARTVAL;
    }

    TypeCheckCtx typeCheckCtx = new TypeCheckCtx(null);
    String defaultPartitionName = HiveConf.getVar(conf, HiveConf.ConfVars.DEFAULTPARTITIONNAME);
    boolean result = true;
    for (Node childNode : astNode.getChildren()) {
      ASTNode childASTNode = (ASTNode)childNode;

      if (childASTNode.getType() != HiveParser.TOK_PARTVAL) {
        result = getPartExprNodeDesc(childASTNode, conf, astExprNodeMap) && result;
      } else {
        boolean isDynamicPart = childASTNode.getChildren().size() <= 1;
        result = !isDynamicPart && result;
        if (!isDynamicPart) {
          ASTNode partVal = (ASTNode)childASTNode.getChildren().get(1);
          if (!defaultPartitionName.equalsIgnoreCase(unescapeSQLString(partVal.getText()))) {
            astExprNodeMap.put((ASTNode)childASTNode.getChildren().get(0),
                TypeCheckProcFactory.genExprNode(partVal, typeCheckCtx).get(partVal));
          }
        }
      }
    }
    return result;
  }
  // ...
}

抽象構文木 (AST) にデフォルト・パーティションの値があったら特別扱いするようだ. astExprNodeMap はどんな意味の記録なんだろうか.

childASTNode.getChildren().get(0) みたいなASTの走査しなきゃいけないの辛い, どういう文法なのかのコメントが欲しい.

org.apache.hive.ql.parse.DDLSemanticAnalyzer

/**
 * DDLSemanticAnalyzer.
 *
 */
public class DDLSemanticAnalyzer extends BaseSemanticAnalyzer {
  // ...
  public DDLSemanticAnalyzer(QueryState queryState, Hive db) throws SemanticException {
    super(queryState, db);
    reservedPartitionValues = new HashSet<String>();
    // Partition can't have this name
    reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.DEFAULTPARTITIONNAME));
    reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.DEFAULT_ZOOKEEPER_PARTITION_NAME));
    // Partition value can't end in this suffix
    reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.METASTORE_INT_ORIGINAL));
    reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.METASTORE_INT_ARCHIVED));
    reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.METASTORE_INT_EXTRACTED));
    hiveAuthorizationTaskFactory = createAuthorizationTaskFactory(conf, db);
  }
  // ...
  /**
   * Certain partition values are are used by hive. e.g. the default partition
   * in dynamic partitioning and the intermediate partition values used in the
   * archiving process. Naturally, prohibit the user from creating partitions
   * with these reserved values. The check that this function is more
   * restrictive than the actual limitation, but it's simpler. Should be okay
   * since the reserved names are fairly long and uncommon.
   */
  private void validatePartitionValues(Map<String, String> partSpec)
      throws SemanticException {

    for (Entry<String, String> e : partSpec.entrySet()) {
      for (String s : reservedPartitionValues) {
        String value = e.getValue();
        if (value != null && value.contains(s)) {
          throw new SemanticException(ErrorMsg.RESERVED_PART_VAL.getMsg(
              "(User value: " + e.getValue() + " Reserved substring: " + s + ")"));
        }
      }
    }
  }
  // ...
}

デフォルト・パーティションの値を予約語として登録して, それを含めた予約語が出てくるパーティション値をエラーとして例外を飛ばすっぽい. ちなみに reservedPartitionValues はDDLSemanticAnalyzerのフィールド.

org.apache.hive.ql.parse.SemanticAnalyzer

/**
 * Implementation of the semantic analyzer. It generates the query plan.
 * There are other specific semantic analyzers for some hive operations such as
 * DDLSemanticAnalyzer for ddl operations.
 */

public class SemanticAnalyzer extends BaseSemanticAnalyzer {
  // ...
  @SuppressWarnings("nls")
  protected Operator genFileSinkPlan(String dest, QB qb, Operator input)
      throws SemanticException {

    RowResolver inputRR = opParseCtx.get(input).getRowResolver();
    QBMetaData qbm = qb.getMetaData();
    Integer dest_type = qbm.getDestTypeForAlias(dest);

    Table dest_tab = null; // destination table if any
    boolean destTableIsAcid = false; // should the destination table be written to using ACID
    boolean destTableIsTemporary = false;
    boolean destTableIsMaterialization = false;
    Partition dest_part = null;// destination partition if any
    Path queryTmpdir = null; // the intermediate destination directory
    Path dest_path = null; // the final destination directory
    TableDesc table_desc = null;
    int currentTableId = 0;
    boolean isLocal = false;
    SortBucketRSCtx rsCtx = new SortBucketRSCtx();
    DynamicPartitionCtx dpCtx = null;
    LoadTableDesc ltd = null;
    ListBucketingCtx lbCtx = null;
    Map<String, String> partSpec = null;

    switch (dest_type.intValue()) {
    case QBMetaData.DEST_TABLE: {

      dest_tab = qbm.getDestTableForAlias(dest);
      destTableIsAcid = AcidUtils.isAcidTable(dest_tab);
      destTableIsTemporary = dest_tab.isTemporary();

      // Is the user trying to insert into a external tables
      if ((!conf.getBoolVar(HiveConf.ConfVars.HIVE_INSERT_INTO_EXTERNAL_TABLES)) &&
          (dest_tab.getTableType().equals(TableType.EXTERNAL_TABLE))) {
        throw new SemanticException(
            ErrorMsg.INSERT_EXTERNAL_TABLE.getMsg(dest_tab.getTableName()));
      }

      partSpec = qbm.getPartSpecForAlias(dest);
      dest_path = dest_tab.getPath();

      // If the query here is an INSERT_INTO and the target is an immutable table,
      // verify that our destination is empty before proceeding
      if (dest_tab.isImmutable() &&
          qb.getParseInfo().isInsertIntoTable(dest_tab.getDbName(),dest_tab.getTableName())){
        try {
          FileSystem fs = dest_path.getFileSystem(conf);
          if (! MetaStoreUtils.isDirEmpty(fs,dest_path)){
            LOG.warn("Attempted write into an immutable table : "
                + dest_tab.getTableName() + " : " + dest_path);
            throw new SemanticException(
                ErrorMsg.INSERT_INTO_IMMUTABLE_TABLE.getMsg(dest_tab.getTableName()));
          }
        } catch (IOException ioe) {
            LOG.warn("Error while trying to determine if immutable table has any data : "
                + dest_tab.getTableName() + " : " + dest_path);
          throw new SemanticException(ErrorMsg.INSERT_INTO_IMMUTABLE_TABLE.getMsg(ioe.getMessage()));
        }
      }

      // check for partition
      List<FieldSchema> parts = dest_tab.getPartitionKeys();
      if (parts != null && parts.size() > 0) { // table is partitioned
        if (partSpec == null || partSpec.size() == 0) { // user did NOT specify partition
          throw new SemanticException(generateErrorMessage(
              qb.getParseInfo().getDestForClause(dest),
              ErrorMsg.NEED_PARTITION_ERROR.getMsg()));
        }
        dpCtx = qbm.getDPCtx(dest);
        if (dpCtx == null) {
          dest_tab.validatePartColumnNames(partSpec, false);
          dpCtx = new DynamicPartitionCtx(dest_tab, partSpec,
              conf.getVar(HiveConf.ConfVars.DEFAULTPARTITIONNAME),
              conf.getIntVar(HiveConf.ConfVars.DYNAMICPARTITIONMAXPARTSPERNODE));
          qbm.setDPCtx(dest, dpCtx);
        }

        if (!HiveConf.getBoolVar(conf, HiveConf.ConfVars.DYNAMICPARTITIONING)) { // allow DP
          throw new SemanticException(generateErrorMessage(
              qb.getParseInfo().getDestForClause(dest),
              ErrorMsg.DYNAMIC_PARTITION_DISABLED.getMsg()));
        }
        if (dpCtx.getSPPath() != null) {
          dest_path = new Path(dest_tab.getPath(), dpCtx.getSPPath());
        }
        if ((dest_tab.getNumBuckets() > 0)) {
          dpCtx.setNumBuckets(dest_tab.getNumBuckets());
        }
      }

      boolean isNonNativeTable = dest_tab.isNonNative();
      if (isNonNativeTable) {
        queryTmpdir = dest_path;
      } else {
        queryTmpdir = ctx.getTempDirForPath(dest_path);
      }
      if (dpCtx != null) {
        // set the root of the temporary path where dynamic partition columns will populate
        dpCtx.setRootPath(queryTmpdir);
      }
      // this table_desc does not contain the partitioning columns
      table_desc = Utilities.getTableDesc(dest_tab);

      // Add sorting/bucketing if needed
      input = genBucketingSortingDest(dest, input, qb, table_desc, dest_tab, rsCtx);

      idToTableNameMap.put(String.valueOf(destTableId), dest_tab.getTableName());
      currentTableId = destTableId;
      destTableId++;

      lbCtx = constructListBucketingCtx(dest_tab.getSkewedColNames(),
          dest_tab.getSkewedColValues(), dest_tab.getSkewedColValueLocationMaps(),
          dest_tab.isStoredAsSubDirectories(), conf);

      // Create the work for moving the table
      // NOTE: specify Dynamic partitions in dest_tab for WriteEntity
      if (!isNonNativeTable) {
        AcidUtils.Operation acidOp = AcidUtils.Operation.NOT_ACID;
        if (destTableIsAcid) {
          acidOp = getAcidType(table_desc.getOutputFileFormatClass());
          checkAcidConstraints(qb, table_desc, dest_tab);
        }
        ltd = new LoadTableDesc(queryTmpdir, table_desc, dpCtx, acidOp);
        ltd.setReplace(!qb.getParseInfo().isInsertIntoTable(dest_tab.getDbName(),
            dest_tab.getTableName()));
        ltd.setLbCtx(lbCtx);
        loadTableWork.add(ltd);
      } else {
        // This is a non-native table.
        // We need to set stats as inaccurate.
        setStatsForNonNativeTable(dest_tab);
      }

      WriteEntity output = null;

      // Here only register the whole table for post-exec hook if no DP present
      // in the case of DP, we will register WriteEntity in MoveTask when the
      // list of dynamically created partitions are known.
      if ((dpCtx == null || dpCtx.getNumDPCols() == 0)) {
        output = new WriteEntity(dest_tab, determineWriteType(ltd, isNonNativeTable));
        if (!outputs.add(output)) {
          throw new SemanticException(ErrorMsg.OUTPUT_SPECIFIED_MULTIPLE_TIMES
              .getMsg(dest_tab.getTableName()));
        }
      }
      if ((dpCtx != null) && (dpCtx.getNumDPCols() >= 0)) {
        // No static partition specified
        if (dpCtx.getNumSPCols() == 0) {
          output = new WriteEntity(dest_tab, determineWriteType(ltd, isNonNativeTable), false);
          outputs.add(output);
        }
        // part of the partition specified
        // Create a DummyPartition in this case. Since, the metastore does not store partial
        // partitions currently, we need to store dummy partitions
        else {
          try {
            String ppath = dpCtx.getSPPath();
            ppath = ppath.substring(0, ppath.length() - 1);
            DummyPartition p =
                new DummyPartition(dest_tab, dest_tab.getDbName()
                    + "@" + dest_tab.getTableName() + "@" + ppath,
                    partSpec);
            output = new WriteEntity(p, WriteEntity.WriteType.INSERT, false);
            outputs.add(output);
          } catch (HiveException e) {
            throw new SemanticException(e.getMessage(), e);
          }
        }
      }

      ctx.getLoadTableOutputMap().put(ltd, output);
      break;
    }
    case QBMetaData.DEST_PARTITION: {

      dest_part = qbm.getDestPartitionForAlias(dest);
      dest_tab = dest_part.getTable();
      destTableIsAcid = AcidUtils.isAcidTable(dest_tab);
      if ((!conf.getBoolVar(HiveConf.ConfVars.HIVE_INSERT_INTO_EXTERNAL_TABLES)) &&
          dest_tab.getTableType().equals(TableType.EXTERNAL_TABLE)) {
        throw new SemanticException(
            ErrorMsg.INSERT_EXTERNAL_TABLE.getMsg(dest_tab.getTableName()));
      }

      Path tabPath = dest_tab.getPath();
      Path partPath = dest_part.getDataLocation();

      // If the query here is an INSERT_INTO and the target is an immutable table,
      // verify that our destination is empty before proceeding
      if (dest_tab.isImmutable() &&
          qb.getParseInfo().isInsertIntoTable(dest_tab.getDbName(),dest_tab.getTableName())){
        try {
          FileSystem fs = partPath.getFileSystem(conf);
          if (! MetaStoreUtils.isDirEmpty(fs,partPath)){
            LOG.warn("Attempted write into an immutable table partition : "
                + dest_tab.getTableName() + " : " + partPath);
            throw new SemanticException(
                ErrorMsg.INSERT_INTO_IMMUTABLE_TABLE.getMsg(dest_tab.getTableName()));
          }
        } catch (IOException ioe) {
            LOG.warn("Error while trying to determine if immutable table partition has any data : "
                + dest_tab.getTableName() + " : " + partPath);
          throw new SemanticException(ErrorMsg.INSERT_INTO_IMMUTABLE_TABLE.getMsg(ioe.getMessage()));
        }
      }

      // if the table is in a different dfs than the partition,
      // replace the partition's dfs with the table's dfs.
      dest_path = new Path(tabPath.toUri().getScheme(), tabPath.toUri()
          .getAuthority(), partPath.toUri().getPath());

      queryTmpdir = ctx.getTempDirForPath(dest_path);
      table_desc = Utilities.getTableDesc(dest_tab);

      // Add sorting/bucketing if needed
      input = genBucketingSortingDest(dest, input, qb, table_desc, dest_tab, rsCtx);

      idToTableNameMap.put(String.valueOf(destTableId), dest_tab.getTableName());
      currentTableId = destTableId;
      destTableId++;

      lbCtx = constructListBucketingCtx(dest_part.getSkewedColNames(),
          dest_part.getSkewedColValues(), dest_part.getSkewedColValueLocationMaps(),
          dest_part.isStoredAsSubDirectories(), conf);
      AcidUtils.Operation acidOp = AcidUtils.Operation.NOT_ACID;
      if (destTableIsAcid) {
        acidOp = getAcidType(table_desc.getOutputFileFormatClass());
        checkAcidConstraints(qb, table_desc, dest_tab);
      }
      ltd = new LoadTableDesc(queryTmpdir, table_desc, dest_part.getSpec(), acidOp);
      ltd.setReplace(!qb.getParseInfo().isInsertIntoTable(dest_tab.getDbName(),
          dest_tab.getTableName()));
      ltd.setLbCtx(lbCtx);

      loadTableWork.add(ltd);
      if (!outputs.add(new WriteEntity(dest_part, (ltd.getReplace() ?
          WriteEntity.WriteType.INSERT_OVERWRITE :
          WriteEntity.WriteType.INSERT)))) {
        throw new SemanticException(ErrorMsg.OUTPUT_SPECIFIED_MULTIPLE_TIMES
            .getMsg(dest_tab.getTableName() + "@" + dest_part.getName()));
      }
      break;
    }
    case QBMetaData.DEST_LOCAL_FILE:
      isLocal = true;
      // fall through
    case QBMetaData.DEST_DFS_FILE: {
      dest_path = new Path(qbm.getDestFileForAlias(dest));

      if (isLocal) {
        // for local directory - we always write to map-red intermediate
        // store and then copy to local fs
        queryTmpdir = ctx.getMRTmpPath();
      } else {
        // otherwise write to the file system implied by the directory
        // no copy is required. we may want to revisit this policy in future

        try {
          Path qPath = FileUtils.makeQualified(dest_path, conf);
          queryTmpdir = ctx.getTempDirForPath(qPath);
        } catch (Exception e) {
          throw new SemanticException("Error creating temporary folder on: "
              + dest_path, e);
        }
      }
      String cols = "";
      String colTypes = "";
      ArrayList<ColumnInfo> colInfos = inputRR.getColumnInfos();

      // CTAS case: the file output format and serde are defined by the create
      // table command rather than taking the default value
      List<FieldSchema> field_schemas = null;
      CreateTableDesc tblDesc = qb.getTableDesc();
      if (tblDesc != null) {
        field_schemas = new ArrayList<FieldSchema>();
        destTableIsTemporary = tblDesc.isTemporary();
        destTableIsMaterialization = tblDesc.isMaterialization();
      }

      boolean first = true;
      for (ColumnInfo colInfo : colInfos) {
        String[] nm = inputRR.reverseLookup(colInfo.getInternalName());

        if (nm[1] != null) { // non-null column alias
          colInfo.setAlias(nm[1]);
        }

        String colName = colInfo.getInternalName();  //default column name
        if (field_schemas != null) {
          FieldSchema col = new FieldSchema();
          if (!("".equals(nm[0])) && nm[1] != null) {
            colName = unescapeIdentifier(colInfo.getAlias()).toLowerCase(); // remove ``
          }
          colName = fixCtasColumnName(colName);
          col.setName(colName);
          String typeName = colInfo.getType().getTypeName();
          // CTAS should NOT create a VOID type
          if (typeName.equals(serdeConstants.VOID_TYPE_NAME)) {
              throw new SemanticException(ErrorMsg.CTAS_CREATES_VOID_TYPE
              .getMsg(colName));
          }
          col.setType(typeName);
          field_schemas.add(col);
        }

        if (!first) {
          cols = cols.concat(",");
          colTypes = colTypes.concat(":");
        }

        first = false;
        cols = cols.concat(colName);

        // Replace VOID type with string when the output is a temp table or
        // local files.
        // A VOID type can be generated under the query:
        //
        // select NULL from tt;
        // or
        // insert overwrite local directory "abc" select NULL from tt;
        //
        // where there is no column type to which the NULL value should be
        // converted.
        //
        String tName = colInfo.getType().getTypeName();
        if (tName.equals(serdeConstants.VOID_TYPE_NAME)) {
          colTypes = colTypes.concat(serdeConstants.STRING_TYPE_NAME);
        } else {
          colTypes = colTypes.concat(tName);
        }
      }

      // update the create table descriptor with the resulting schema.
      if (tblDesc != null) {
        tblDesc.setCols(new ArrayList<FieldSchema>(field_schemas));
      }

      boolean isDestTempFile = true;
      if (!ctx.isMRTmpFileURI(dest_path.toUri().toString())) {
        idToTableNameMap.put(String.valueOf(destTableId), dest_path.toUri().toString());
        currentTableId = destTableId;
        destTableId++;
        isDestTempFile = false;
      }

      boolean isDfsDir = (dest_type.intValue() == QBMetaData.DEST_DFS_FILE);
      loadFileWork.add(new LoadFileDesc(tblDesc, queryTmpdir, dest_path, isDfsDir, cols,
          colTypes));

      if (tblDesc == null) {
        if (qb.getIsQuery()) {
          String fileFormat;
          if (SessionState.get().isHiveServerQuery() &&
                   conf.getBoolVar(HiveConf.ConfVars.HIVE_SERVER2_THRIFT_RESULTSET_SERIALIZE_IN_TASKS)) {
              fileFormat = "SequenceFile";
              HiveConf.setVar(conf, HiveConf.ConfVars.HIVEQUERYRESULTFILEFORMAT, fileFormat);
              table_desc=
                         PlanUtils.getDefaultQueryOutputTableDesc(cols, colTypes, fileFormat,
                           ThriftJDBCBinarySerDe.class);
              // Set the fetch formatter to be a no-op for the ListSinkOperator, since we'll
              // write out formatted thrift objects to SequenceFile
              conf.set(SerDeUtils.LIST_SINK_OUTPUT_FORMATTER, NoOpFetchFormatter.class.getName());
          } else {
              fileFormat = HiveConf.getVar(conf, HiveConf.ConfVars.HIVEQUERYRESULTFILEFORMAT);
              table_desc =
                         PlanUtils.getDefaultQueryOutputTableDesc(cols, colTypes, fileFormat,
                           LazySimpleSerDe.class);
          }
        } else {
          table_desc = PlanUtils.getDefaultTableDesc(qb.getDirectoryDesc(), cols, colTypes);
        }
      } else {
        table_desc = PlanUtils.getTableDesc(tblDesc, cols, colTypes);
      }

      if (!outputs.add(new WriteEntity(dest_path, !isDfsDir, isDestTempFile))) {
        throw new SemanticException(ErrorMsg.OUTPUT_SPECIFIED_MULTIPLE_TIMES
            .getMsg(dest_path.toUri().toString()));
      }
      break;
    }
    default:
      throw new SemanticException("Unknown destination type: " + dest_type);
    }

    input = genConversionSelectOperator(dest, qb, input, table_desc, dpCtx);

    inputRR = opParseCtx.get(input).getRowResolver();

    ArrayList<ColumnInfo> vecCol = new ArrayList<ColumnInfo>();

    if (updating() || deleting()) {
      vecCol.add(new ColumnInfo(VirtualColumn.ROWID.getName(), VirtualColumn.ROWID.getTypeInfo(),
          "", true));
    } else {
      try {
        StructObjectInspector rowObjectInspector = (StructObjectInspector) table_desc
            .getDeserializer(conf).getObjectInspector();
        List<? extends StructField> fields = rowObjectInspector
            .getAllStructFieldRefs();
        for (int i = 0; i < fields.size(); i++) {
          vecCol.add(new ColumnInfo(fields.get(i).getFieldName(), TypeInfoUtils
              .getTypeInfoFromObjectInspector(fields.get(i)
                  .getFieldObjectInspector()), "", false));
        }
      } catch (Exception e) {
        throw new SemanticException(e.getMessage(), e);
      }
    }

    RowSchema fsRS = new RowSchema(vecCol);

    // The output files of a FileSink can be merged if they are either not being written to a table
    // or are being written to a table which is not bucketed
    // and table the table is not sorted
    boolean canBeMerged = (dest_tab == null || !((dest_tab.getNumBuckets() > 0) ||
        (dest_tab.getSortCols() != null && dest_tab.getSortCols().size() > 0)));

    // If this table is working with ACID semantics, turn off merging
    canBeMerged &= !destTableIsAcid;

    // Generate the partition columns from the parent input
    if (dest_type.intValue() == QBMetaData.DEST_TABLE
        || dest_type.intValue() == QBMetaData.DEST_PARTITION) {
      genPartnCols(dest, input, qb, table_desc, dest_tab, rsCtx);
    }

    FileSinkDesc fileSinkDesc = new FileSinkDesc(
      queryTmpdir,
      table_desc,
      conf.getBoolVar(HiveConf.ConfVars.COMPRESSRESULT),
      currentTableId,
      rsCtx.isMultiFileSpray(),
      canBeMerged,
      rsCtx.getNumFiles(),
      rsCtx.getTotalFiles(),
      rsCtx.getPartnCols(),
      dpCtx,
      dest_path);

    fileSinkDesc.setHiveServerQuery(SessionState.get().isHiveServerQuery());
    // If this is an insert, update, or delete on an ACID table then mark that so the
    // FileSinkOperator knows how to properly write to it.
    if (destTableIsAcid) {
      AcidUtils.Operation wt = updating() ? AcidUtils.Operation.UPDATE :
          (deleting() ? AcidUtils.Operation.DELETE : AcidUtils.Operation.INSERT);
      fileSinkDesc.setWriteType(wt);
      acidFileSinks.add(fileSinkDesc);
    }

    fileSinkDesc.setTemporary(destTableIsTemporary);
    fileSinkDesc.setMaterialization(destTableIsMaterialization);

    /* Set List Bucketing context. */
    if (lbCtx != null) {
      lbCtx.processRowSkewedIndex(fsRS);
      lbCtx.calculateSkewedValueSubDirList();
    }
    fileSinkDesc.setLbCtx(lbCtx);

    // set the stats publishing/aggregating key prefix
    // the same as directory name. The directory name
    // can be changed in the optimizer but the key should not be changed
    // it should be the same as the MoveWork's sourceDir.
    fileSinkDesc.setStatsAggPrefix(fileSinkDesc.getDirName().toString());
    if (!destTableIsMaterialization &&
            HiveConf.getVar(conf, HIVESTATSDBCLASS).equalsIgnoreCase(StatDB.fs.name())) {
      String statsTmpLoc = ctx.getTempDirForPath(dest_path).toString();
      fileSinkDesc.setStatsTmpDir(statsTmpLoc);
      LOG.debug("Set stats collection dir : " + statsTmpLoc);
    }

    if (dest_part != null) {
      try {
        String staticSpec = Warehouse.makePartPath(dest_part.getSpec());
        fileSinkDesc.setStaticSpec(staticSpec);
      } catch (MetaException e) {
        throw new SemanticException(e);
      }
    } else if (dpCtx != null) {
      fileSinkDesc.setStaticSpec(dpCtx.getSPPath());
    }

    Operator output = putOpInsertMap(OperatorFactory.getAndMakeChild(
        fileSinkDesc, fsRS, input), inputRR);

    if (ltd != null && SessionState.get() != null) {
      SessionState.get().getLineageState()
          .mapDirToFop(ltd.getSourcePath(), (FileSinkOperator) output);
    } else if ( queryState.getCommandType().equals(HiveOperation.CREATETABLE_AS_SELECT.getOperationName())) {

      Path tlocation = null;
      String tName = Utilities.getDbTableName(tableDesc.getTableName())[1];
      try {
        Warehouse wh = new Warehouse(conf);
        tlocation = wh.getTablePath(db.getDatabase(tableDesc.getDatabaseName()), tName);
      } catch (MetaException|HiveException e) {
        throw new SemanticException(e);
      }

      SessionState.get().getLineageState()
              .mapDirToFop(tlocation, (FileSinkOperator) output);
    }

    if (LOG.isDebugEnabled()) {
      LOG.debug("Created FileSink Plan for clause: " + dest + "dest_path: "
          + dest_path + " row schema: " + inputRR.toString());
    }

    FileSinkOperator fso = (FileSinkOperator) output;
    fso.getConf().setTable(dest_tab);
    fsopToTable.put(fso, dest_tab);
    // the following code is used to collect column stats when
    // hive.stats.autogather=true
    // and it is an insert overwrite or insert into table
    if (dest_tab != null && conf.getBoolVar(ConfVars.HIVESTATSAUTOGATHER)
        && conf.getBoolVar(ConfVars.HIVESTATSCOLAUTOGATHER)
        && ColumnStatsAutoGatherContext.canRunAutogatherStats(fso)) {
      if (dest_type.intValue() == QBMetaData.DEST_TABLE) {
        genAutoColumnStatsGatheringPipeline(qb, table_desc, partSpec, input, qb.getParseInfo()
            .isInsertIntoTable(dest_tab.getDbName(), dest_tab.getTableName()));
      } else if (dest_type.intValue() == QBMetaData.DEST_PARTITION) {
        genAutoColumnStatsGatheringPipeline(qb, table_desc, dest_part.getSpec(), input, qb
            .getParseInfo().isInsertIntoTable(dest_tab.getDbName(), dest_tab.getTableName()));

      }
    }
    return output;
  }
  // ...
}

メソッド長ぇ.

どうもここを読むと良さそうな気がする.

とりあえず今日はここまで. 全体の設計意図が把握できないうちはソースコードの中で迷子になるなぁ.

]]>
Sun, 28 Aug 2016 00:00:00 +0900
http://tink.elliptium.net/2016/08/26/hive_note_2.html http://tink.elliptium.net/2016/08/26/hive_note_2.html <![CDATA[Hive覚え書き・その2]]> Hive覚え書き・その2

今はデフォルト・パーティションについて調査中.

ソースコード

enum ConfVars にある DEFAULTPARTITIONNAME で参照されていると思われるので調査.

grep -nIR 'DEFAULTPARTITIONNAME' --include '*.java' ./*
./common/src/java/org/apache/hadoop/hive/conf/HiveConf.java:509:    DEFAULTPARTITIONNAME("hive.exec.default.partition.name", "__HIVE_DEFAULT_PARTITION__",
./common/src/java/org/apache/hadoop/hive/conf/HiveConf.java:3908:    ConfVars.DEFAULTPARTITIONNAME.varname,
./common/src/test/org/apache/hadoop/hive/conf/TestHiveConf.java:94:    checkHiveConf("test.var.hiveconf.property", ConfVars.DEFAULTPARTITIONNAME.getDefaultValue());
./hcatalog/core/src/main/java/org/apache/hive/hcatalog/mapreduce/DynamicPartitionFileRecordWriterContainer.java:91:    this.HIVE_DEFAULT_PARTITION_VALUE = HiveConf.getVar(context.getConfiguration(), HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./metastore/src/java/org/apache/hadoop/hive/metastore/hbase/HBaseStore.java:927:      defaultPartName = HiveConf.getVar(getConf(), HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./metastore/src/java/org/apache/hadoop/hive/metastore/hbase/HBaseUtils.java:1011:          partitionKeys.add(HiveConf.getVar(conf, HiveConf.ConfVars.DEFAULTPARTITIONNAME));
./metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java:135:    defaultPartName = HiveConf.getVar(conf, ConfVars.DEFAULTPARTITIONNAME);
./metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java:2491:      defaultPartName = HiveConf.getVar(getConf(), HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql/exec/ColumnStatsTask.java:364:            this.conf.getVar(ConfVars.DEFAULTPARTITIONNAME) : partVal.toString());
./ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java:1105:        if (part.getName().equals(conf.getVar(HiveConf.ConfVars.DEFAULTPARTITIONNAME))) {
./ql/src/java/org/apache/hadoop/hive/ql/exec/TableScanOperator.java:258:    defaultPartitionName = HiveConf.getVar(hconf, HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql/metadata/Hive.java:2569:    String defaultPartitionName = HiveConf.getVar(conf, ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql/optimizer/ppr/PartitionPruner.java:476:    String defaultPartitionName = conf.getVar(HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql/parse/BaseSemanticAnalyzer.java:1474:    String defaultPartitionName = HiveConf.getVar(conf, HiveConf.ConfVars.DEFAULTPARTITIONNAME);
./ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java:244:    reservedPartitionValues.add(HiveConf.getVar(conf, ConfVars.DEFAULTPARTITIONNAME));
./ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java:6594:              conf.getVar(HiveConf.ConfVars.DEFAULTPARTITIONNAME),
./ql/src/java/org/apache/hadoop/hive/ql/stats/StatsUtils.java:438:                ci.getType().getTypeName(), conf.getVar(ConfVars.DEFAULTPARTITIONNAME)));

今のところクエリのwhere句でデフォルト・パーティション値を使ったときにどういう動作をするかを知りたいので (たぶんQuery Languageの略である) qlプロジェクトを見ていく. まずはクエリの処理の部分を探す.

とりあえずファイルを一覧する. よく見るとmavenの標準的な構成じゃないんですね.

tree -L 6 ./ql/src/java/
./ql/src/java/
└── org
    └── apache
        ├── hadoop
        │   └── hive
        │       ├── llap
        │       │   ├── ChannelOutputStream.java
        │       │   ├── DebugUtils.java
        │       │   ├── LlapOutputFormat.java
        │       │   ├── LlapOutputFormatService.java
        │       │   └── LlapRecordWriter.java
        │       ├── metastore
        │       │   └── SynchronizedMetaStoreClient.java
        │       └── ql
        │           ├── CommandNeedRetryException.java
        │           ├── CompilationOpContext.java
        │           ├── Context.java
        │           ├── Driver.java
        │           ├── DriverContext.java
        │           ├── ErrorMsg.java
        │           ├── HashTableLoaderFactory.java
        │           ├── HiveDriverRunHook.java
        │           ├── HiveDriverRunHookContext.java
        │           ├── HiveDriverRunHookContextImpl.java
        │           ├── MapRedStats.java
        │           ├── QueryDisplay.java
        │           ├── QueryPlan.java
        │           ├── QueryProperties.java
        │           ├── QueryState.java
        │           ├── debug
        │           ├── exec
        │           ├── history
        │           ├── hooks
        │           ├── index
        │           ├── io
        │           ├── lib
        │           ├── lockmgr
        │           ├── log
        │           ├── metadata
        │           ├── optimizer
        │           ├── parse
        │           ├── plan
        │           ├── ppd
        │           ├── processors
        │           ├── security
        │           ├── session
        │           ├── stats
        │           ├── thrift
        │           ├── tools
        │           ├── txn
        │           ├── udf
        │           └── util
        └── tez
            └── dag
                └── api
                    └── TaskSpecBuilder.java

33 directories, 22 files

org.apache.hadoop.hive.ql あたりを探せば良さそう.

今日はここまで.

]]>
Fri, 26 Aug 2016 00:00:00 +0900
http://tink.elliptium.net/2016/08/23/hive_note_1.html http://tink.elliptium.net/2016/08/23/hive_note_1.html <![CDATA[Hive覚え書き・その1]]> Hive覚え書き・その1

Hiveについて調べたことをつらつらと書く.

デフォルト・パーティション

まずはHiveのダイナミック・インポートのときに作成されるデフォルト・パーティションの扱いについて, 実装から調べていく.

ソースコード

GithubにあるHiveレポジトリのミラー (https://github.com/apache/hive) をforkした https://github.com/cocoatomo/hive をクローンして作業する. まずは取っ掛かりとして定義されている場所を探す.

cd .../hive
grep -nIRl '__HIVE_DEFAULT_PARTITION__' ./*
./common/src/java/org/apache/hadoop/hive/common/FileUtils.java
./common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
./hcatalog/core/src/main/java/org/apache/hive/hcatalog/mapreduce/FileOutputCommitterContainer.java
./hcatalog/core/src/main/java/org/apache/hive/hcatalog/mapreduce/HCatFileUtil.java
./ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
./ql/src/java/org/apache/hadoop/hive/ql/exec/TableScanOperator.java
./ql/src/test/queries/clientnegative/default_partition_name.q
./ql/src/test/queries/clientpositive/alter_partition_change_col.q
./ql/src/test/queries/clientpositive/alter_partition_coltype.q
./ql/src/test/queries/clientpositive/alter_table_cascade.q
./ql/src/test/queries/clientpositive/annotate_stats_part.q
./ql/src/test/queries/clientpositive/default_partition_name.q
./ql/src/test/queries/clientpositive/dynamic_partition_skip_default.q
./ql/src/test/queries/clientpositive/dynpart_sort_opt_vectorization.q
./ql/src/test/queries/clientpositive/dynpart_sort_optimization.q
./ql/src/test/queries/clientpositive/extrapolate_part_stats_full.q
./ql/src/test/queries/clientpositive/extrapolate_part_stats_partial.q
./ql/src/test/queries/clientpositive/insert_into_with_schema.q
./ql/src/test/results/beelinepositive/default_partition_name.q.out
./ql/src/test/results/beelinepositive/load_dyn_part14.q.out
./ql/src/test/results/clientnegative/default_partition_name.q.out
./ql/src/test/results/clientpositive/alter_partition_change_col.q.out
./ql/src/test/results/clientpositive/alter_partition_coltype.q.out
./ql/src/test/results/clientpositive/alter_table_cascade.q.out
./ql/src/test/results/clientpositive/analyze_table_null_partition.q.out
./ql/src/test/results/clientpositive/annotate_stats_part.q.out
./ql/src/test/results/clientpositive/autoColumnStats_1.q.out
./ql/src/test/results/clientpositive/autoColumnStats_2.q.out
./ql/src/test/results/clientpositive/default_partition_name.q.out
./ql/src/test/results/clientpositive/dynamic_partition_skip_default.q.out
./ql/src/test/results/clientpositive/dynpart_sort_opt_vectorization.q.out
./ql/src/test/results/clientpositive/dynpart_sort_optimization.q.out
./ql/src/test/results/clientpositive/extrapolate_part_stats_full.q.out
./ql/src/test/results/clientpositive/extrapolate_part_stats_partial.q.out
./ql/src/test/results/clientpositive/insert_into_with_schema.q.out
./ql/src/test/results/clientpositive/llap/dynpart_sort_opt_vectorization.q.out
./ql/src/test/results/clientpositive/llap/dynpart_sort_optimization.q.out
./ql/src/test/results/clientpositive/llap/stats_only_null.q.out
./ql/src/test/results/clientpositive/llap/vector_non_string_partition.q.out
./ql/src/test/results/clientpositive/llap_partitioned.q.out
./ql/src/test/results/clientpositive/load_dyn_part14.q.out
./ql/src/test/results/clientpositive/load_dyn_part14_win.q.out
./ql/src/test/results/clientpositive/spark/load_dyn_part14.q.out
./ql/src/test/results/clientpositive/spark/stats_only_null.q.out
./ql/src/test/results/clientpositive/stats_only_null.q.out
./ql/src/test/results/clientpositive/tez/dynpart_sort_opt_vectorization.q.out
./ql/src/test/results/clientpositive/tez/dynpart_sort_optimization.q.out
./ql/src/test/results/clientpositive/tez/stats_only_null.q.out
./ql/src/test/results/clientpositive/tez/vector_non_string_partition.q.out
./ql/src/test/results/clientpositive/vector_non_string_partition.q.out

最初の6行より後はテストの期待される結果のようなので無視.

定義場所っぽい HiveConf.java を見る.

2 space tabなのか. 珍しい気もする.

public static enum ConfVars {
  // ...
  DEFAULTPARTITIONNAME("hive.exec.default.partition.name", "__HIVE_DEFAULT_PARTITION__",
      "The default partition name in case the dynamic partition column value is null/empty string or any other values that cannot be escaped. \n" +
      "This value must not contain any special character used in HDFS URI (e.g., ':', '%', '/' etc). \n" +
      "The user has to be aware that the dynamic partition value should not contain this value to avoid confusions."),
  // ...
}

おそらく他の場所では DEFAULTPARTITIONNAME の名前で参照されているのだろう.

念の為他の場所も見ておく.

grep -nIR '__HIVE_DEFAULT_PARTITION__' --include '*.java' ./*
./common/src/java/org/apache/hadoop/hive/common/FileUtils.java:275:        // __HIVE_DEFAULT_PARTITION__ was the return value for escapePathName
./common/src/java/org/apache/hadoop/hive/common/FileUtils.java:276:        return "__HIVE_DEFAULT_PARTITION__";
./common/src/java/org/apache/hadoop/hive/conf/HiveConf.java:509:    DEFAULTPARTITIONNAME("hive.exec.default.partition.name", "__HIVE_DEFAULT_PARTITION__",
./hcatalog/core/src/main/java/org/apache/hive/hcatalog/mapreduce/FileOutputCommitterContainer.java:705:      dynPathSpec = dynPathSpec.replaceAll("__HIVE_DEFAULT_PARTITION__", "*");
./hcatalog/core/src/main/java/org/apache/hive/hcatalog/mapreduce/HCatFileUtil.java:71:        sb.append("__HIVE_DEFAULT_PARTITION__");
./ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java:1201:        // if length of (prefix/ds=__HIVE_DEFAULT_PARTITION__/000000_0) is greater than max key prefix
./ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java:1205:        // Now that (prefix/ds=__HIVE_DEFAULT_PARTITION__) is hashed to a smaller prefix it will
./ql/src/java/org/apache/hadoop/hive/ql/exec/TableScanOperator.java:187:          // to the special partition, __HIVE_DEFAULT_PARTITION__.

コメントだけに現れるのかと思いきや, 案外リテラルも使われている. 大丈夫なんだろか.

今日はここまで.

]]>
Tue, 23 Aug 2016 00:00:00 +0900
http://tink.elliptium.net/2016/06/25/good_math_has_been_published_in_japanese.html http://tink.elliptium.net/2016/06/25/good_math_has_been_published_in_japanese.html <![CDATA[数学が気になる全てのプログラマへ!!『グッド・マス』が日本語で出ます]]> 数学が気になる全てのプログラマへ!!『グッド・マス』が日本語で出ます

対象をかなり大きくしましたがオススメしたい気持ちは本当ですよ :)

アフィリエイトリンクはウィジェットのデザインが良いので使ってるだけです. アフィリエイト無しのリンクはこちらです.

『グッド・マス』とは

MARKCCによる数学ブログの Good Math, Bad Math, この記事をまとめて本として出版されたのが Good Math です. MARKCCさん自身はプログラマであり, その視点から数学を題材にたくさんのブログ記事を書いています. その語り口は軽妙といった感じで堅苦しくなく, MARKCCさん自身のワクワクした気持ちを文章に乗せています.

『グッド・マス』の面白いところ

各部ごとに見どころがあるのですが, この本の面白いところは部を跨いで題材が関係を持つところです.
第I部で出てきたペアノ数が第IV部でPrologで実装されたり第VI部でチャーチ数として登場したり.
第IV部で出てきた一階述語論理が第V部の集合と強い結び付きがあったり.
第II部の黄金比でちらっと出てきた連分数が, 第III部でさらに話が広げられたり.

私はこういう「一見異なる見た目のものが実は同じものだった」という話が大好きで, これが数学の魅力の1つだと思っています.

この本では関連のある話題への参照があるので, それを辿って色んな部を読んでみるのも面白いかもしれません.

(個別の話になると長くなってしまいそうなので, それはまた別の機会に語ろうと思います.)

続きを読む...

]]>
Sat, 25 Jun 2016 00:00:00 +0900
http://tink.elliptium.net/2016/06/01/my_impression_of_topology_section_2.html http://tink.elliptium.net/2016/06/01/my_impression_of_topology_section_2.html <![CDATA[位相のイメージ (その2) -- 位相の定義]]> 位相のイメージ (その2) – 位相の定義

位相のイメージ (その1) では位相に関わる概念の全体像について語りました. いわば全体地図の上でスタート地点とゴール地点とそこを結ぶ道筋を説明しました. この記事ではもう少し詳細に各概念の定義を比較していこうと思います.

各種定義

これから位相の話をするために, まず各種概念の定義を見ていきましょう. と言っても, 大学の講義のように形式的な定義を紹介するだけでは, この記事を書く意味が無いので具体例も交じえて説明していきます. 例には4点集合 \(S = \{1, 2, 3, 4\}\) を使います. これは要素が4つの集合です. 抽象的な概念を考えるには, これくらい小さな簡単な例の方が良いのです.

続きを読む...

]]>
Wed, 01 Jun 2016 00:00:00 +0900
http://tink.elliptium.net/2016/04/02/my_impression_of_topology_section_1.html http://tink.elliptium.net/2016/04/02/my_impression_of_topology_section_1.html <![CDATA[位相のイメージ (その1)]]> 位相のイメージ (その1)

大学数学の講義で比較的早い段階で勉強する科目に「位相」(topology) があります. 他の大学数学の科目と同様, 高校数学とのギャップに苦しむ人が多いんじゃないかと思います. そんな人に向けて, 自分が持った位相のイメージや解釈を書き出していってみます. 位相を理解する手掛かりになれば嬉しいです.

使用する教科書

私自身が大学の講義で教科書として使った, 裳華房の数学シリーズ『集合と位相』(内田伏一・著) を使用します.

手元に無くても困らないように記事を書くつもりですが, 自身で証明の細かいところを追ったり, これから記事として書く内容の裏付けを取ったりするのであれば, 是非買ってください. きちんと習得すれば3000円弱の出費は安いものだと思います.

続きを読む...

]]>
Sat, 02 Apr 2016 00:00:00 +0900
http://tink.elliptium.net/2015/12/31/summary_on_2015.html http://tink.elliptium.net/2015/12/31/summary_on_2015.html <![CDATA[2015年のまとめ]]> 2015年のまとめ

2015年のまとめ的な記事が流れてきたので, その流れに便乗して今年のまとめ記事書いてみます.

続きを読む...

]]>
Thu, 31 Dec 2015 00:00:00 +0900
http://tink.elliptium.net/2015/12/14/language_implementation_advent_calendar_2015.html http://tink.elliptium.net/2015/12/14/language_implementation_advent_calendar_2015.html <![CDATA[Java に独自の型検査処理を追加する方法]]> Java に独自の型検査処理を追加する方法

これは 言語実装 Advent Calendar 2015 の 14 日目の記事です.

Pluggable Annotation Processing API (JSR 269) による Functor の型検査 という以前に書いた記事を, Advent Calendar 用に再構成, 要約したものです.

Note

この記事では主に型情報にアクセスする方法について書きます. それ以外の部分は上記の元記事を参照してください.

Java で函手を書いてみたかった

そもそもは「Java で函手を書く」という無茶をしてみたかっただけです. 無茶は承知の上で, 書こうとする過程でどんな障害があって, どうやって回避できるかを探りたかったのです.

函手について解説するのはこの記事の目的ではないので, 厳密な定義などについては触れません. 函手 (関手, Functor) の定義は 独習 Scalaz — 圏の例 あたりを読んでください.

何をしたかったかをソースコードで表せば,

import java.util.function.Function;

public class MyFunctor<A> {

    public <B> MyFunctor<B> map(Function<A, B> morphism) {
        // ...
    }

}

こんなメソッド map を持ったクラスを実装するのがゴールです.

続きを読む...

]]>
Mon, 14 Dec 2015 00:00:00 +0900
http://tink.elliptium.net/2015/12/01/zero_to_the_power_of_zero.html http://tink.elliptium.net/2015/12/01/zero_to_the_power_of_zero.html <![CDATA[0の0乗]]> 0の0乗

0の0乗の正解がネット検索しても見つからないので作成した。 を発端とした議論に便乗した記事です. (つぶやいた内容をまとめただけですが. 笑)

]]>
Tue, 01 Dec 2015 00:00:00 +0900
http://tink.elliptium.net/2015/10/07/type_checking_on_functor_with_pluggable_annotation_processing_api_jsr_269.html http://tink.elliptium.net/2015/10/07/type_checking_on_functor_with_pluggable_annotation_processing_api_jsr_269.html <![CDATA[Pluggable Annotation Processing API (JSR 269) による Functor の型検査]]> Pluggable Annotation Processing API (JSR 269) による Functor の型検査

https://bitbucket.org/cocoatomo/categorical/ で開発している, 注釈による型クラスの実現手法の解説です.

発端

うらがみさんが Scala による Functor の実装をしていて,

trait Functor[A, F[_]] { self: F[A] =>
  def map[B](f: A => B): F[B]
}

(https://github.com/backpaper0/sandbox/blob/134a658c42eb14354ce53fa95931d5a32672fc74/functor-applicative-study/src/main/scala/functor-applicative-study.scala#L5-L7 より引用)

興味深かったので Java でもなんとかならないかと試していました.

続きを読む...

]]>
Wed, 07 Oct 2015 00:00:00 +0900
http://tink.elliptium.net/2015/09/20/applicative_functors_are_strong_lax_monoical_functors.html http://tink.elliptium.net/2015/09/20/applicative_functors_are_strong_lax_monoical_functors.html <![CDATA[applicative 函手は strong lax monoical 函手]]> applicative 函手は strong lax monoical 函手

前回 (圏論における applicative functor) の続きです.

タイトルから想像できる通り, 調べる対象が applicative 函手から strong lax monoidal 函手に変わっただけで, まだ完全には理解してません.

読んだ論文

酒井さんからご紹介いただいた “Applicative Programming with Effects” [Conor_and_Ross_2008] という論文を読んでみます.

Abstract に “In this paper, we introduce Applicative functors” とあるので, この論文で applicative functor が初登場したのかな??

論文の構成

節の内容を要約するとこんな感じになります.

  1. Introduction

    applicative が隠れているところをいくつか紹介

  2. The Applicative class

    Haskell の Applicative 型クラスの定義

  3. Traversing data structures

    Traversable 型クラスは Applicative 型クラスから作れる

  4. Monoids are phantom Applicative functors

    Monoid 函手はファントム (亡霊?) Applicative 函手

  5. Applicative versus Monad?

    ApplicativeMonad の関係

  6. Applicative functors and Arrows

    Applicative 函手と Arrows の関係

  7. Applicative functors, categorically

    Applicative を圏論の視点で見る

    一番知りたかった内容

  8. Conclusion

    まとめ

    Applicative は色んなものの抽象化

    モナドとかコモナドとかアローとかアプリカティブとか圏論の構造の種類がめっちゃ増えてるけど, それで怖がらせるとか不安にさせるのはよくないよね. 表記法がそれぞれ違っててごちゃごちゃしてるのが良くないから, なんとか再利用できるようにしよう. この論文では [| f u_1 ... u_n |] という表記で書いてみたよ.

    みたいなことも書いてあって面白い.

    (ここで使われている mathbb っぽい括弧は, \(\LaTeX\) では stmaryrd パッケージ [stmaryrd]\usepackage{stmaryrd} と読み込むと \llbracket, \rrbracket と使えるそうです.)

続きを読む...

]]>
Sun, 20 Sep 2015 00:00:00 +0900
http://tink.elliptium.net/2015/08/25/a_question_about_scalaz_naturaltransformation.html http://tink.elliptium.net/2015/08/25/a_question_about_scalaz_naturaltransformation.html <![CDATA[scalaz.NaturalTransformation についての疑問]]>

scalaz.NaturalTransformation についての疑問

発端

という がくぞさん の疑問があって

平日夜にすごいH本をちょびちょび読む会 (通称: ちょびよみ) での話題にしよう, という流れになりました.

解説準備用のメモとして, この記事を書いておきます.

続きを読む...

]]>
Tue, 25 Aug 2015 00:00:00 +0900
http://tink.elliptium.net/2015/08/05/applicative_functor_in_terms_of_category_theory.html http://tink.elliptium.net/2015/08/05/applicative_functor_in_terms_of_category_theory.html <![CDATA[圏論における applicative functor]]> 圏論における applicative functor

applicative functor って何だ??

平日夜にすごいH本をちょびちょび読む会 17回目 いのちをだいじにしながら「すごいHaskellたのしく学ぼう!」を少しずつ読んでいく という読書会 (?) をやっていて, applicative functor というものが登場してきました.

使い方は分かるのですが, 数学を専攻してた人なので圏論での意味付けが気になって仕方ありません.

そこでこんなふうにつぶやいたところ, 予想以上に多くの反応をもらえました. せっかくなので記録のためにメモっておきます.

続きを読む...

]]>
Wed, 05 Aug 2015 00:00:00 +0900
http://tink.elliptium.net/2015/06/28/spark_casual_1.html http://tink.elliptium.net/2015/06/28/spark_casual_1.html <![CDATA[Spark Casual Talk #1 に行ってきました]]>

Spark Casual Talk #1 に行ってきました

最近データ解析や機械学習で色々と話題な Apache Spark ですが, その勉強会があるというので行ってきました. 一般枠が 123 人のところに 150 人の申し込みがあり, Spark が注目されているのが分かります.

勉強会の構成は, 発表が 2 つと LT が 6 本で 2 時間というものでした. 名前に casual とある通り, これから Spark に触れようという人でも気軽に参加できる内容だったと思います. (一部の LT は除く^-^;)

イベントページ: http://connpass.com/event/15575/ Togetter: http://togetter.com/li/838406

気になった話題

個人的に気になった話題について書いていきます. 個々の内容については, イベントページにアップロードされている資料や Togetter のつぶやきを参照してください.

DataFrame

メキメキ開発の進む Apache Sparkのいまとこれから: http://www.slideshare.net/hadoopxnttdata/nttdata-spark-casual-talk-1

2 つ目の発表「メキメキ開発の進む Apache Sparkのいまとこれから」で, Spark SQL が使っている DataFrame が紹介されていました. DataFrame は Spark SQL のためだけのものかと思っていましたが, DataFrame API も用意されていて Scala や Python など他の言語からも操作ができるようです. DataFrame には最適化の機能もあり, どの言語で書かれていても最適化の恩恵を等しく受けられるそうです.

Project Tungsten

Spark Summit 2015 参加報告: http://www.slideshare.net/potix2_jp/spark-summit-2015

1 つ目の発表「Spark Summit 2015 参加報告」で, Project Tungsten というパフォーマンス改善の取り組みが紹介されていました. このプロジェクトは, DataFrame で記述された論理計画を実行する部分を高速化しようというものです. 現在のハードウェアの流れを見ているとストレージやネットワークに比べて CPU の高速化が遅れているので, そこを補う方向を目指しているようです.

From DataFrames to Tungsten: A Peek into Spark’s Future: http://www.slideshare.net/databricks/2015-0616-spark-summit

JIRA にプロジェクトの親 issue があり (SPARK-7075 https://issues.apache.org/jira/browse/SPARK-7075) 関連 issue はその下にぶら下がっています.

Notebook

「メキメキ開発の進む Apache Sparkのいまとこれから」で Apache Zeppelin, 「Hueで実現する、SparkとSQLのためのノートブック」で CDH の Hue と複数の発表で notebook の話題が出てきていてかなり気になりました. notebook というのは私が勝手に呼んでいるツールの種類の名前で, だいたい次の機能を備えているものを notebook に分類しています.

  • データの対話的操作
  • コマントの結果やデータをグラフなどの画像で表現

昔からあるもので言えば, Mathematica, Maple, Sage (これは比較的最近) などの数式処理ソフト, 2 つ目の機能を実現するもので言えば Excel などの表計算ソフト, gnuplot などのグラフ化ツールなどがあります.

Spark にはデフォルトで pyspark から IPython notebook が利用できます. IPython は元々は Python の便利な REPL だったのですが, バージョン 0.12 からブラウザを UI とした notebook 機能が追加され, バージョン 4.0 からはそこを Jupyter という別プロジェクトとして発展させていくそうです.

上の機能に加え notebook ツールにあると便利な機能はこんなところです.

  • 実行したコマンドの記録, 再現可能な形式での保存, 再実行

    gnuplot の save, load コマンド相当のもの: http://lowrank.net/gnuplot/intro/basic.html#exit

  • 複数人での画面の共有

    複数人でチャットしつつ, それぞれがコマンドを入力し, その結果を共有できたり.

    Google Wave がイメージに近かったのですが, なんで死んでしもうたんや……

なぜ私が notebook ツールに注目するかと言えば, それが分析とレポーティングに役立つツールだからです. くだけた言い方をすれば, notebook ツールはあるデータを自分や他の人に分かりやすく見せ, 対象について理解を深め, 何らかの行動につなげるために役立つ重要なツールだと思っています.

色んなことを知ることができた勉強会だったので Spark Casual #2 にも参加してみようと思います.

ではでは.

]]>
Sun, 28 Jun 2015 00:00:00 +0900
http://tink.elliptium.net/2014/12/10/getting_start_with_asakusa_gradle_plugin.html http://tink.elliptium.net/2014/12/10/getting_start_with_asakusa_gradle_plugin.html <![CDATA[Asakusa Gradle Plugin に触れてみよう]]> Asakusa Gradle Plugin に触れてみよう

この記事は Asakusa Framework Advent Calendar 2014 の 12/10 の記事です.

Asakusa Framework のことは名前と用途くらいは知ってるものとして, Asakusa Gradle Plugin について書いていきます.

基本的に Asakusa Gradle Plugin利用ガイド の抜粋みたいな文章なので, そちらも参考に読んでみてください.

Asakusa Gradle Plugin とは

コンパイルが必要な言語でのソフトウェアの開発の流れは、

  1. ファイルにプログラムを記述
  2. コンパイル
  3. テスト
  4. リリース用にビルド

となると思います.

Asakusa バッチアプリケーションを開発する上で, このリストの 2, 3, 4 番の項目に 1 つ加えた

  • 開発環境の準備
  • コンパイル
  • テスト
  • リリース用にビルド

の 4 つの作業をサポートするのが Asakusa Gradle Plugin (以下 Gradle Plugin) です.

そこで使っているビルドツール (正確にはビルドツールのための汎用フレームワーク?) は Gradle です. ここでは Gradle には深入りしないので, ユーザガイド や書籍に当たってみてください.

先程の 4 つの作業をどうサポートするかについて, これから (おそらく数記事に分けて) 解説していきます. CLI 編と GUI 編の解説が必要なのですが, まずは CLI 編から入っていきます.

まずは実行しよう

何はともあれ Gradle Plugin を触ってみましょう.

Asakusa を使ったサンプルプロジェクト asakusa-example-project-0.7.1.tar.gz が公開されているので, これに対して Gradle Plugin を使っていきます.

## java はインストールされてるものとします
$ java -version
java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b12)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

## 環境変数 JAVA_HOME も設定しておいてください
$ echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home

## 開発用ディレクトリに移動
$ cd どこか適当なディレクトリ

## サンプルプロジェクトをダウンロード. 手動でも可.
$ wget http://www.asakusafw.com/download/gradle-plugin/asakusa-example-project-0.7.1.tar.gz
## もしくは
$ curl -O http://www.asakusafw.com/download/gradle-plugin/asakusa-example-project-0.7.1.tar.gz

## ファイルを展開
$ tar xvf asakusa-example-project-0.7.1.tar.gz

## プロジェクトディレクトリに移動
$ cd asakusa-example-project/

ここまで上手く行けば, Gradle Plugin を使う環境が整いました. さっそく次のコマンドを打って Gradle Plugin でできることを見ていきましょう.

$ ./gradlew tasks
Downloading http://services.gradle.org/distributions/gradle-2.1-bin.zip
..........................(中略)
:tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Asakusa Framework Build tasks
-----------------------------
compileBatchapp - Compiles the Asakusa DSL java source with Asakusa DSL Compiler.
compileDMDL - Compiles the DMDL scripts with DMDL Compiler.
generateHiveDDL - Generates Hive DDL file from Data Models [Experimental].
generateTestbook - Generates the template Excel books for TestDriver.
generateThunderGateDataModel - Executes DDLs and generates ThunderGate data models.
jarBatchapp - Assembles a jar archive containing compiled batch applications.
summarizeYaessJob - Analyzes YAESS job execution from log file [Experimental].
testRunBatchapp - Executes Asakusa Batch Application [Experimental].

Asakusa Framework Organizer tasks
---------------------------------
assembleAsakusafw - Assembles a tarball containing framework files for deployment.
attachBatchapps - Attaches batch applications to assemblies.
attachComponentCore - Attaches framework core components to assemblies.
attachComponentDevelopment - Attaches development tools to assemblies.
attachComponentDirectIo - Attaches Direct I/O components to assemblies.
attachComponentExtension - Attaches framework extension components to assemblies.
attachComponentOperation - Attaches operation tools to assemblies.
attachComponentTesting - Attaches testing tools to assemblies.
attachComponentThunderGate - Attaches ThunderGate components to assemblies.
attachComponentWindGate - Attaches WindGate components to assemblies.
attachComponentWindGateSsh - Attaches WindGate SSH components to assemblies.
attachComponentYaess - Attaches YAESS components to assemblies.
attachComponentYaessHadoop - Attaches Yaess Hadoop bridge components to assemblies.
attachExtensionDirectIoHive - Attaches Direct I/O Hive extensions to assemblies.
attachExtensionWindGateRetryable - Attaches WindGate retryable extensions to assemblies.
attachExtensionYaessJobQueue - Attaches YAESS JobQueue client extensions to assemblies.
attachExtensionYaessTools - Attaches YAESS extra tools to assemblies.
cleanAssembleAsakusafw - Deletes the assembly files and directories.
installAsakusafw - Installs Asakusa Framework to $ASAKUSA_HOME using 'dev' profile.
updateAsakusafw - Updates Asakusa Framework on $ASAKUSA_HOME using 'dev' profile.

Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles classes 'main'.
clean - Deletes the build directory.
jar - Assembles a jar archive containing the main classes.
testClasses - Assembles classes 'test'.

Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]

Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.

Help tasks
----------
components - Displays the components produced by root project 'asakusa-example-project'.
dependencies - Displays all dependencies declared in root project 'asakusa-example-project'.
dependencyInsight - Displays the insight into a specific dependency in root project 'asakusa-example-project'.
help - Displays a help message
projects - Displays the sub-projects of root project 'asakusa-example-project'.
properties - Displays the properties of root project 'asakusa-example-project'.
tasks - Displays the tasks runnable from root project 'asakusa-example-project'.

IDE tasks
---------
cleanEclipse - Cleans all Eclipse files.
eclipse - Generates all Eclipse files.

Verification tasks
------------------
check - Runs all checks.
test - Runs the unit tests.

Other tasks
-----------
wrapper

Rules
-----
Pattern: clean<TaskName>: Cleans the output files of a task.
Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration.
Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration.
Pattern: attachConf<Target>: Attaches asakusafw custom distribution files to assembly.

To see all tasks and more detail, run with --all.

BUILD SUCCESSFUL

Total time: 49.6 secs

こんな出力が出ていたら Gradle Plugin は無事動いています! 初めての Gradle Plugin の実行成功おめでとう!!

どうも上手く動いていないようなら, 環境変数 JAVA_HOME の設定や各コマンドが異常終了していないか echo $? で 1 つ 1 つ確かめてみてください.

出力の解説

如何せん出力が多いので, 必要なところから解説していきます.

この ./gradlew tasks というコマンドで出力したのはタスクの一覧です. タスクとはその名の通り「何らかの作業」です. ./gradlew タスク名 という形式で Gradle に何らかの作業を指示します. 先程のコマンドを例に出せば, tasks という名前のタスクはタスク一覧を出す処理を行うものでした.

Asakusa Framework Build tasks
-----------------------------

とある下に並んでいるのは Gradle Plugin が提供する Asakusa プロジェクト用のタスクです. これらのタスクは, 最初のリストで上げた作業のうち主に

  • コンパイル
  • テスト

に関わる作業をサポートします.

Asakusa Framework Organizer tasks
---------------------------------

とある下に並んでいるのも, 同じく Gradle Plugin が提供する Asakusa プロジェクト用のタスクです. こちらのタスクは主に

  • 開発環境の準備
  • リリース用にビルド

のサポートを受け持ちます.

他にもタスクはありますが, いっぺんに説明しても混乱すると思うので, まずはこのくらいにしておきます.

では

  • Asakusa Gradle Plugin とは何ぞや? 何のためにあるの?
  • Gradle Plugin の実行方法
  • Gradle には「タスク」というものがあり, Asakusa 用のタスクを使って Asakusa バッチアプリケーションを開発していく

あたりを伝えられたと思うので, 今日はこのくらいで.

]]>
Wed, 10 Dec 2014 00:00:00 +0900
http://tink.elliptium.net/2014/12/09/syobochim_and_kotlin_advent_calendar_12_09.html http://tink.elliptium.net/2014/12/09/syobochim_and_kotlin_advent_calendar_12_09.html <![CDATA[Syobochim and Kotlin Advent Calendar 12/09]]> Syobochim and Kotlin Advent Calendar 12/09

この記事は しょぼちむ Advent Calendar 2014Kotlin Advent Calendar 2014 の 12/09 分です.

昨日のしょぼちむ Advent Calendar 2014 の記事は @skrb さんの 追うしょぼちむ です.

昨日の Kotlin Advent Calendar 2014 の記事は @yy_yank さんの 別のプログラミング言語を使うということ #ktac2014 です.

しょぼちむさんをフォローした日

普段 Java を使ってお仕事しているのもあり, JVM 言語には興味がありました. 数カ月前のある日,「Kotlin アイドルという方が Twitter にいるようだ. 何か Kotlin について分かるかな」と思いフォローした結果,

あれ?(′・ω・`)

えっえっ??

それから月日が経ち, ちょうど Advent Calendar の時期になったので, 「無いなら仕方無い, 自分で情報を集めよう! それを Advent Calendar の記事にしよう!」と思いこのブログ記事を書いています.

Java から Kotlin へ

とは言え, どこから始めていいのやら, 情報はどこにまとまっているのか分かってないです… そして, 自分としては Java に慣れているので, Java と比べてどういう言語なのかをまず知りたいのです…… 「じゃあ, Java を知ってる人が Kotlin を始めるのにちょうどいい情報を集めよう」というのが出発点であり, 目的でもあります.

さて肝心の記事は?

今回の記事はちょっと変わったところに書きました.

続きを読む...

]]>
Tue, 09 Dec 2014 00:00:00 +0900
http://tink.elliptium.net/2014/12/01/adventures_in_wonder_infinite_land.html http://tink.elliptium.net/2014/12/01/adventures_in_wonder_infinite_land.html <![CDATA[Adventures in Wonder-infinite-land]]> Adventures in Wonder-infinite-land

タイトルの元ネタはあれです. 直訳すれば「不思議の無限の国の冒険」かな.

この記事の発端

何かと思えば, ちょっと前に話題になってた「素数を全部掛ける」話のようです.

全ての素数の積は偶数だと思ったんだけど

「無限」という言葉から

たぶんほんわかとした無限大のイメージって

\[1, 2, 3,\dots,\infty\ (←ここらへんにある何か)\]

くらいなものだと思います.

ここから発想すると色々不思議なことが起こり「無限って何だ?」となることがあるので, それを紹介して無限の雰囲気を見てもらおうというのが, この記事の趣旨です.

無限を作ってみる

上に挙げた \(1, 2, 3,\dots,\infty\) をひとまずこう考えてみましょう.

\[\begin{split}&1, \\ &1 + 1 = 2, \\ &2 + 1 = 3, \\ &3 + 1 = 4, \\ &\dots, \\ &\infty\end{split}\]

つまり,「1 つ前の数字に 1 を足して次の数字を作り, これを延々繰り返した先に無限大があると思おう」ということです. そうするとこんなふうに書けるので, まぁイメージとズレてはいないんじゃないでしょうか?

\[1 + 1 + 1 + \cdots = \infty\]

無限は偶数? 奇数?

まずこの無限大は偶数でしょうか? 奇数でしょうか?

ある人はこう主張します.

\[(1 + 1) + (1 + 1) + \cdots = 2 + 2 + \cdots = \infty\]

と書けるから偶数だ, と.

別の人はこう主張します.

\[1 + (1 + 1) + (1 + 1) + \cdots = 1 + 2 + 2 + \cdots = \infty\]

いやいやこう書けるから奇数だ, と.

さてどっちが正しいのでしょうか?

無限は自然数? 有理数?

さらにひねくれた人が表れてこう主張します.

\[\begin{split}&1 + 1 + 1 + \cdots \\ =&(\frac{1}{2} + \frac{1}{2}) + (\frac{1}{2} + \frac{1}{2}) + \cdots \\ =& \frac{1}{2} + (\frac{1}{2} + \frac{1}{2}) + \cdots \\ =& \frac{1}{2} + 1 + 1 + \cdots \\ =& \infty\end{split}\]

だから無限大は自然数じゃない有理数なのさ, と.

「えー, 元の定義から考えても, 明らかにそれはおかしいよー. だって後ろに \(\frac{1}{2}\) は残り続けるんでしょ?」と反論しても, 「端数の \(\frac{1}{2}\) はどんどん後ろに行ってるから問題無いでしょ?」と, 返すために借金する借金地獄や「返さないんじゃない, 一生借りてるだけだ」という誰かのセリフを連想させるような返事が返ってきます.

無限ホテル

無限に先送りすることで何とかなってしまうお話として, 無限ホテルというのがあります. これは無限に部屋のあるホテルが舞台で, そのホテルには 1 号室から順に 2 号室, 3 号室と部屋番号が付いています.

ある日そのホテルは満室だったのですが, 予約の無い人がどうしても泊めてくれと訪れました. 管理人は悩んだのですが, 一計を講じて彼を泊めることにしました. その方法とは全ての部屋にいる人達に「今の部屋番号に 1 を足した部屋に移ってください.」と指示を出しました. その甲斐あって 1 号室に空きができ, 彼は部屋を得ることができました.

\[\begin{split}\begin{matrix} 部屋番号 & 1 & & 2 & & 3 & & \dots \\ & & \searrow & & \searrow & & \searrow & \\ 移動後 & 1 & & 2 & & 3 & & \dots \\ & \uparrow & & & & & & \end{matrix}\end{split}\]

落ち着く間も無く, 今度は無限の席数のあるバスで無限人数の客が突然押し掛けました. 手違いでホテルの予約ができておらず, しょうがなく近くにあるこのホテルに来たということです. また困ったことになった管理人ですが, 再び良いアイディアを思い付きました. 彼の指示はこうです「ホテルにご宿泊の人は, 今の部屋番号の 2 倍の部屋番号へ移動をお願いします. バスでお越しの方はバスの座席番号の 2 倍から 1 を引いた部屋へお泊まりください.」 全員の協力の甲斐もあって, 既に宿泊していた人は偶数の部屋番号の部屋へ, バスでやって来た人達は奇数の部屋番号の部屋へ入ることができました.

\[\begin{split}\begin{matrix} 部屋番号 & 1 & & 2 & & 3 & & 4 & & 5 & & 6 & & \dots \\ & & \searrow & & \searrow & & \searrow & & & & & & & \\ & & & \downarrow & & \searrow & & \rightarrow & \rightarrow & \rightarrow & & & & \\ & & & \downarrow & & & \searrow & & & & \searrow & & & \\ 移動後 & 1 & & 2 & & 3 & & 4 & & 5 & & 6 & & \dots \\ & \uparrow & & & & \uparrow & & & & \uparrow & & & & \end{matrix}\end{split}\]

さすがにもう追加のお客さんは来ないだろうと思っていた管理人は慌てました. 無限台数の無限の座席のあるバスに無限人数の客を乗せてやってきたのです. 悩みに悩んだ管理人ですが, すごい案を思い付いたのです.

部屋番号 or 座席番号 "n"
↓
. | ...
. | ...
3 | 6 9 ...
2 | 3 5 8 ...
1 | 1 2 4 7 ... ← 新しく移る部屋番号
- + -----------
    0 1 2 3 ... ← バス番号 "m"

ホテルもバス番号の \(0\) 番を振って, バスと同じように扱うことにしました. バス番号を \(m\), 部屋番号か座席番号を \(n\) として, そこにいるお客様にお願いの指示を出しました. 「お客様は

\[\frac{(m + n)(m + n + 1)}{2} - m\]

へお移りください」と. するとどうでしょう. 上の図にあるようにバスも部屋も無限個あるのに, 全員がホテルの部屋へ泊まることができました.

ここまでの話で無限の不思議さが伝わったと思います.

(ここに書いたものは, 色々な本を読んだ記憶から話を再構築しています.)

数学的帰納法

hishidama さんの記事にあった数学的帰納法にも言及しておきます. 「数学的帰納法は、無限に対しては使えない」という事実に驚いたそうですが, このことについてやや専門的な解説をしておきます.

数学的帰納法は無限個の証明をするためのものです.

まず \(n = 1\) についてある命題 \(P(n)\) を証明します. 命題には変数 \(n\) を含むので, 関数の引数のように書いてあります.

次にある \(k \in \mathbb{N}\) について命題 \(P(k)\) が正しいと仮定して \(P(k + 1)\) を証明します. 論理式で書けば \(\forall k \in \mathbb{N}, P(k) \to P(k + 1)\) となります.

この 2 つの命題 \(P(1)\)\(\forall k \in \mathbb{N}, P(k) \to P(k + 1)\) から \(P(n)\ (n \in \mathbb{N})\) が導けるのが数学的帰納法です. (ここでは \(\mathbb{N}\) は 1 以上の整数としています. 宗教戦争をするつもりはありませんので悪しからず.)

さて, ここで問題にしたいのが「数学的帰納法で \(P(\infty)\) は証明できているのか?」です. 答えから言ってしまえば「 \(\mathbb{N}\) には \(\infty\) は含まれないので \(P(\infty)\) は証明できていない」です. ただ, これだと「じゃあ \(\mathbb{N}\)\(\infty\) が含まれないのは何故か?」という話になりそうです. ここらへんのことをちゃんと説明するには私の知識では不足なので, 別の説明で済ます (ごまかすw) ことにします.

「無限」と言うときには「いくらでも大きく取れる有限な数」を指していることがあります. ただしこれは「どの自然数よりも大きい何か」というのはちょっと違います. ここの「どの自然数よりも大きい何か」を扱うために「極限」という概念 (手法) があります. (他にも無限を扱う手法はあるらしいですが, ここでは極限の話をしましょう.)

極限

高校数学までではやや曖昧に定義されている (「限りなく近付く」とか) 極限ですが, 大学数学からは厳密な定義があります. 有名な「ε-δ論法」です. (大学数学の壁の 1 つとして有名?)

「ε-δ論法」が言ってることは次のようなものです. 「ある数列 \(a_n\) がある値 \(a\) に収束する」とは 「 \(a\) にどれだけ近い (が \(a\) ではない) 数 \(b\) を指定しても, 数列のあるところから先の \(a_n\)\(b\) より \(a\) に近い」ということです. と. 言葉で書いてもややこしいし, 論理式で書いても慣れない人にはややこしい……

ε-δ論法については深入りせず, 次の点を指摘するだけに留めます. 「収束値は, 数列の各々の値とは性質が違うことがある.」

例えば \(a_n = 1/n\) という数列があったとき, 数列の各々の値は正の数です. しかし, これの収束値は \(0\) であり「正の数」ではありません. この数列の極限を取る操作では「正の数」という性質は保たれていません.

また別の例として, 有理数の列の極限を取って無理数を得る例を挙げましょう. \(a_1 = 1,\ a_{n+1} = (a_n + 2/a_n)/2\) で数列を定めます. 有名なニュートン法による \(\sqrt{2}\) の近似列です.

この数列では計算方法から各々の値は有理数です. しかし収束値は無理数です. ここでは極限を取ることによって「有理数」という性質が無くなり「無理数」になっています.

hishidama さんのところで言及されている対角線の長さの話は, 極限操作 (= 極限を取ること) が「曲線の長さ」を保存しないという話です.

極限が保存しない性質があるというのを逆に言えば, 有限の操作では得られない性質が極限操作によって得られる, ということです. 有理数から実数を作成するところがまさにそれです.

無限大に向かう極限

あ, 収束する話ばかりで無限大に発散していく (=「どんどん大きくなる」) 話をするのを忘れていました.

最初に出した無限大へ向かう \(1, 2, 3,\dots\) という数列は \(a_n = n\) と書けますが, これの向かう先が無限大であるということも「ε-δ論法」と同様の定式化ができます.

「ある数列 \(a_n\) が (正の) 無限大に発散する」とは 「どんなに大きな数 (ここでは自然数としておきます) \(b\) を指定しても, 数列のあるところから先の \(a_n\)\(b\) よりも大きい」ということです. 言ってることは「どんどん大きくなる」と変わらないのですが, 大きくなってく途中の \(a_n\) は有限な値であることに注意してください.

この発散する数列においても, 極限操作が数の性質を保存しないことはあります. 例えば, \(1, 3, 5,\dots\) という数列と \(2, 4, 6,\dots\) という数列はどちらも無限大に発散していきますが, 今のところの定義では両者の極限である 2 つの「無限大」は区別できません.

「ずっと奇数だから無限大も奇数」という主張も「ずっと偶数だから無限大も偶数」という主張も同じ理屈を使っているので, 両方とも正しいか両方とも間違っているかのどちらかです. (今のところ) 区別できないこの「無限大」が, 奇数であり同時に偶数であることは有り得ないので, 無限大は奇数でも偶数でもないことになります.

そもそも複数種類ある無限大をごちゃまぜに扱ってるのがマズいことから, それらを区別しようと思うのは自然な流れだと思います. 目的に応じて様々な区別の方法がありますが, 分かりやすいのは解析学や計算量の理論でよく使われる「オーダー」という考え方です. \(1, 2, 3,\dots,\infty\)\(1, 10, 100,\dots,\infty\) では 2 つ目の方が「大きな無限大」だと感じるでしょう. ではどう比較すればいいかと言うと, 小さいと感じる方を大きいと感じる方で割ればいいのです. 数列どうしの割り算なので, こんな数列が生まれます: \(1/1, 2/10, 3/100,\dots\). (厳密な証明は省きますが) この数列は 0 に収束するので, 2 つ目の方が「真に大きな無限」と言えます.

オーダーの話も深めれば様々ありますが, 今回はここまでとしておきます.

終わりに

無限について知っていることをつらつらと書いてみました. 「無限」という単語から, 様々な話題が展開できることが伝われば, この記事の目的は達成できました. 私の力不足により

  • 公理的集合論の文脈における自然数および自然数集合の存在
  • 解析接続による全素数を乗算した値の定式化

という話題は扱えていません. またこれ以外の話の展開もできるでしょう. (参考: 全ての素数の積が偶数なのが納得がいかない数学徒たち)

またネタが思い付いたら, もしくはネタを振られたら, 書こうと思います.

]]>
Mon, 01 Dec 2014 00:00:00 +0900
http://tink.elliptium.net/2014/09/27/starting_with_apache_spark.html http://tink.elliptium.net/2014/09/27/starting_with_apache_spark.html <![CDATA[Apache Spark 始めました]]> Apache Spark 始めました

Apache Spark を触り始めてみました.

環境セットアップ

Spark のソースコードは GitHub 上にあるので, あらかじめ自分のアカウントに fork してから clone しています.

$ git clone git@github.com:cocoatomo/spark.git
$ cd spark

## ビルド
## https://spark.apache.org/docs/latest/building-with-maven.html
$ export MAVEN_OPTS="-Xmx2g -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=512m"
$ mvn -Dhadoop.version=1.2.1 -DskipTests clean package

## 実行
## https://spark.apache.org/docs/latest/index.html
## PySpark REPL の起動
$ ./bin/pyspark --master local[2]
...
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 1.2.0-SNAPSHOT
      /_/

Using Python version 2.7.8 (default, Jul  2 2014 10:14:46)
SparkContext available as sc.
>>> exit()

## Python スクリプトを指定して実行
$ ./bin/spark-submit examples/src/main/python/pi.py 10
...
Pi is roughly 3.145916
...

ちゃんと動いていますね.

PySpark on IPython

pyspark ファイル (実体は bash スクリプト) に IPython を起動できそうな記述があるので, IPython で PySpark を起動してみました.

$ IPYTHON=1 ./bin/pyspark
Python 2.7.8 (default, Jul  2 2014, 10:14:46)
...

## なぜか python コマンドの方が実行される

$ IPYHTON=1 PYSPARK_PYTHON=ipython ./bin/pyspark
Python 2.7.8 (default, Jul  2 2014, 10:14:46)
Type "copyright", "credits" or "license" for more information.

IPython 2.2.0 -- An enhanced Interactive Python.
...

## こっちだと起動した

調べた結果, ./bin/pyspark に問題があったので issue と Pull Request 上げました.

コメントとかの反応待ちになりますが, pyspark スクリプトのテストとかどうするんでしょうね?

]]>
Sat, 27 Sep 2014 00:00:00 +0900
http://tink.elliptium.net/2014/07/25/learn_you_a_haskell_for_great_good_reading_2.html http://tink.elliptium.net/2014/07/25/learn_you_a_haskell_for_great_good_reading_2.html <![CDATA[平日夜にすごいH本をちょびちょび読む会 #2]]> 平日夜にすごいH本をちょびちょび読む会 #2

という読書会に参加してきた.

イベントページ → http://hchobi.connpass.com/event/7523/

シリーズものになりそうなので connpass にしたっぽい.

前回の台風に引き続き, 今回の雷雨と, どうも大雨に見舞われる読書会のようです.

出た話題のメモ

  • P.7 の「関数 conanO’Brien と文字列 “It’s a-me, Conan O’Brien!” は互いに交換できます」の「交換」ってどういうこと?

    • 「関数 conanO’Brien」が現れるところを「文字列 “It’s a-me, Conan O’Brien!”」に置き換えても意味が変わらず, その逆も然り. ということだと思う.
    • 別の言い方をすれば, 文字列リテラルが「文字列リテラルを返す, 引数の数が 0 個の関数」と見れる. ということだと思う.
      • Scala には by-name パラメータというものがあるが, それと関係するか?
        • それとも関係しそうだし, Haskell の評価戦略の非正格性が関係しそうだが, はっきりとは分からない.
  • P.15 [0.1, 0.3 .. 1] の評価結果はみな本の通りなのか?

    • だいたいの人は本の通りだった. [0.1, 0.3, 0.5, 0.90000000, 1.1000000] みたいな人もいた.

    • なんでこうなるんだろう?

  • 関数の定義に関して

    • ある元からある元への対応関係で, 関数と呼べるものを抽象的に書くとこうなる. ということを手を変え品を変え説明してた.

      色々やり取りしたので, 解説を資料にまとめるかもしれないし, やらないかもしれない.

  • 型変数について

    • parametric polymorphism を含む polymorphism の話をした.

    • 普通の変数は「ある値」を表すが, 型変数は「ある型」を表す.「型は集合だ」という点を強調しつつ解説した.

      これも説明を色々したので, 資料にまとめるかもしれない.

]]>
Fri, 25 Jul 2014 00:00:00 +0900
http://tink.elliptium.net/2014/07/13/learn_you_a_haskell_for_great_good_reading_1.html http://tink.elliptium.net/2014/07/13/learn_you_a_haskell_for_great_good_reading_1.html <![CDATA[平日夜にすごいH本をちょびちょび読む会 #1]]> 平日夜にすごいH本をちょびちょび読む会 #1

という読書会に参加してきた.

イベントページ → http://partake.in/events/a804cd6b-17f3-4aca-9b71-6d0a1a641765

話し合った内容のメモ

  • 読書会の頻度どうする?

  • 何を目的に読みたいと思ったの?

    自分の場合は,「型については勉強してたけど, Haskell でそれがどう使われてるのかよく分かっていないので, そこを知りたい」という感じ.

  • 読書会の進め方どうしよ?

    「1 章ずつ読んできて, 分からなかったところを話し合う」という形になった.

  • Haskell ソースコードの読み方の話

    • 関数宣言の書き方の元ネタはあるのか?

      数学では, Int から Int への関数はこんなふうに書く.

      \[f: Int \to Int\]

      これと Haskell の関数宣言部分は似てるのではないか? という話をした.

      f :: Int -> Int
      

      ついでに, \(f: A \to B\) と書いたときの \(A, B\) は集合で, \(A\) の元に \(B\) の元を対応付けるのが数学の関数だ, という話をした.

      「型と集合, 値と集合の元が対応付く」という話をしたら, 何か腑に落ちたところがあったようで嬉しい.

      実は, この考え方の延長戦上に Functor と函手の対応があるのだが, その話は話すべきときまで大事に取っておく.

    • Haskell の関数の書き方

      数学での関数の定義

      \[ \begin{align}\begin{aligned}f: Int \to Int\\f(n) = 2n\end{aligned}\end{align} \]

      と Haskell での関数の定義

      double :: Int -> Int
      double n = 2 * n
      

      の対応を書いて,「1 行目が関数の宣言であり, 型を明示した行」 「2 行目が関数の実体の定義」という話をした.

      例えば Scala だと

      def double(n: Int): Int = 2 * n
      

      と, 型宣言と定義を同時に書いてしまうし, 他の言語でも宣言と定義を同一の文で書くものが多いと思う. (C のプロトタイプ宣言とか Erlang は分けるんだっけ?) それと違って Haskell は 2 行に分ける書き方するんだねー, とか話した.

]]>
Sun, 13 Jul 2014 00:00:00 +0900
http://tink.elliptium.net/2014/06/01/to_be_written_3.html http://tink.elliptium.net/2014/06/01/to_be_written_3.html <![CDATA[執筆予定記事 (その3)]]> 執筆予定記事 (その3)

書く予定のネタ追加

以前書いた同じ内容の記事 (執筆予定記事 (その2)) に追加.

  • 数学の証明について

    • 何をどこまで厳密に示したら証明になるのか?
    • どういう文章が「証明になってる」と言えるのか?

    「この集合の元の最大値は?」程度の例題を交じえながら解説

]]>
Sun, 01 Jun 2014 00:00:00 +0900
http://tink.elliptium.net/2014/05/18/to_be_written.html http://tink.elliptium.net/2014/05/18/to_be_written.html <![CDATA[執筆予定記事 (その2)]]> 執筆予定記事 (その2)

書く予定のネタ追加

以前書いた同じ内容の記事 (執筆予定記事) に追加.

  • 実際の翻訳作業

    • 訳文を読むだけではなくて, C 実装やライブラリの Python コードを読んでいる.
    • 日本語っぽくない部分は, えいやっと変えてしまっている.
  • マサカリを投げることについて

    • 相手が怯えてしまった場合はコミュニケーション失敗. お互いの益にならない.
    • 本来の目的はコミュニケーションを通して相手に望む行動をしてもらうことのはず.
    • 自分自身もたくさん失敗して, 今この考えに至っている.
    • 参考: http://www.slideshare.net/re_3_19/ss-34793007/22

    どうも「マサカリ」という言葉が使われる文脈が広過ぎて, 議論には向かない印象.

    「その指摘の目的は?」くらいのタイトルがちょうど良いくらい.

書きたいものばかり溜まっていく……

]]>
Sun, 18 May 2014 00:00:00 +0900
http://tink.elliptium.net/2014/05/05/getting_started_with_python_document_translation_on_transifex.html http://tink.elliptium.net/2014/05/05/getting_started_with_python_document_translation_on_transifex.html <![CDATA[スタート Python ドキュメント翻訳]]> スタート Python ドキュメント翻訳

以前書いた 翻訳のススメ という記事の続きです. 今回は, 実際に Python ドキュメント翻訳プロジェクトに参加し, どのように作業を進めていくかについて書いていきます.

プロジェクトに参加する

何はともあれメーリングリストに登録しましょう. http://www.python.jp/mailman/listinfo/python-doc-jp オープンソースプロジェクトでよく使われている Mailman です. ここからメールアドレスとパスワードを設定するだけです.

次に文書の翻訳作業を管理する Transifex というサービスにアカウントを作ります. https://www.transifex.com/

作ったアカウントでログインすると https://www.transifex.com/organization/python-doc-ja/dashboard/python-33-ja のページに行けるはずです. ここがプロジェクトのメインページです. プロジェクトの進行状況や, 時系列で翻訳量のグラフが表示されています.

このページ https://www.transifex.com/projects/p/python-33-ja/language/ja/ へ行くと, 翻訳対象の reStructuredText (以下 reST) ファイルが並んでいます. その reST ファイル一覧のヘッダ部分に “Join team” (日本語だとたぶん「チームに参加」とかかな?) ボタンがあるので, それを押せば参加申請完了です. たいていは管理者がメール通知を見て, その日のうちに参加が完了します.

../../../_images/join_team.png

Transifex の仕組み

Transifex では翻訳対象の reST ファイルをリソースと呼んでいます. リソースの一覧 (https://www.transifex.com/projects/p/python-33-ja/language/ja/) から, 翻訳したいリソース名をクリックし, “Translate now” (日本語だとたぶん「翻訳する」かな?) ボタンをクリックして翻訳開始です. リソース名は <ドキュメントの種類>--<ページ名> という形式になっています. 例えば, Python 標準ライブラリ gettext のページ (リソース) (http://docs.python.jp/3.3/library/gettext.html) の名前は library--gettext という名前になっています.

../../../_images/resource_library--gettext.png

ここで翻訳を長く続けるコツですが, 自分が興味のある, 自分が最も読みたいと思うリソースを翻訳することです. 翻訳は機械的にできる作業ではなく, 内容を理解して咀嚼した上で訳文が書けるものなので, 続けるためには自分が知りたい, 翻訳した文章を自分が読みたいと思うものを翻訳すべきです.

続きを読む...

]]>
Mon, 05 May 2014 00:00:00 +0900
http://tink.elliptium.net/2014/04/26/a_suggestion_on_translation.html http://tink.elliptium.net/2014/04/26/a_suggestion_on_translation.html <![CDATA[翻訳のススメ]]> 翻訳のススメ

技術的な内容の文章の翻訳について. 私がなんで翻訳活動をしているのかを, 翻訳をしてみたい人へ向けて書きます.

そもそも翻訳について

O’Reilly さん, KADOKAWA (旧アスキー・メディアワークス) さん, オーム社, さんを始め, 英語で書かれた技術書の訳書は多く出版されています. 他の言語での事情は知りませんが, 日本語への翻訳の需要はかなりあると考えて良いでしょう.

逆に「英語で読む方がより新しい情報を得られる」というメリットや「訳書が出続けると, 英語を読まない人が減らない」という指摘もあります. (c.f. http://anond.hatelabo.jp/20111230052116) 日本の英語教育の話も絡みそうで, なかなか難しい話だと思います.

「翻訳は必要なのだろうか? それとも不要もしくは, すべきでないのだろうか?」と迷ったときもありますが, 結局, 今もボランティア (オープンソース活動の一部になるのかな?) の翻訳活動を続けています. そんな私の経験について少し話をします.

私の翻訳活動

私は Python ドキュメント日本語翻訳プロジェクト というプロジェクトに参加しています. 文字通り, Python の英語のドキュメントを日本語に訳し, 公開するプロジェクトです. プログラミング言語はバージョンを上げながら更新されていくものなので, それに合わせてドキュメントも更新されていき, 終わりの無い翻訳作業になります.

Python のドキュメントは初心者から中級者あたりを対象とし, 非常に手厚く文章が用意されています. そこには初心者向けのチュートリアルや用語集も含まれています. そのためこれを翻訳することは, 日本語が母国語の初心者には役に立つ資料を作ることになるでしょう. Python は標準ライブラリの数が多いため, 詳細を知らないライブラリも多々あります. その仕様が詳細に書いてあるこの文書は, 新しいライブラリを使うときに有用です.

続きを読む...

]]>
Sat, 26 Apr 2014 00:00:00 +0900
http://tink.elliptium.net/2014/04/14/ideals_varieties_and_algorithms_reading.html http://tink.elliptium.net/2014/04/14/ideals_varieties_and_algorithms_reading.html <![CDATA[Ideals, Varieties, and Algorithms 読書会]]> Ideals, Varieties, and Algorithms 読書会

イベントページ

Ideals, Varieties, and Algorithms 読書会 #1 という勉強会に行ってきました.

勉強会の内容

代数幾何の分野のグレブナー基底とその計算に関係するあたりを扱った本です. 内容のレベルとしては, 日本の大学の数学科 2, 3 回生あたりを対象にしているようです.

勉強会のペースとしては, 1 週に 1 回で 1 節をやっていくのが目安になりました. 今日は初めてだったので, 順々に 1 ページずつ読むことにしました.

演習問題はその節の内容を読んだ次の週にやることになりました. というのは演習問題を解くのには, その節の内容が分かってないといけないので, 自習でそこまでやるのは厳しいだろうという話になり, 第 1 節の演習は来週やります.

今週扱った内容は,「多項式」「アフィン空間」「アフィン空間上の関数としての多項式」の定義と, それに関連するちょっとした命題の証明でした.

久し振りの代数幾何

実は自分は数学科修士で, 学部のときの卒業ゼミでは代数幾何が専門の先生に指導を受けていました. ゼミの内容は楕円曲線だったのですが, 先生の影響で友達と代数幾何の本を読んで, 轟沈したりしてました. そんなわけで第 1 章は懐しい内容なのです. 第 2 章からはちゃんとやったことのない「グレブナー基底」の話になっていくのですごく楽しみです.

また risa/asir をいじってみようかな. risa/asir → http://www.math.kobe-u.ac.jp/Asir/asir-ja.html

それでは.

]]>
Mon, 14 Apr 2014 00:00:00 +0900
http://tink.elliptium.net/2014/04/01/animato_for_asakusa_framework_operator.html http://tink.elliptium.net/2014/04/01/animato_for_asakusa_framework_operator.html <![CDATA[Animato for Asakusa Framework Operator]]> Animato for Asakusa Framework Operator

ソースコード

@MasterJoinUpdate
public abstract updateCodeB(
    @Key(group = "codeA") CodeConvMst master,
    @Key(group = "codeA") SomeTrn tx
) {
    tx.setCodeBOption(master.getCodeBOption());
}

出力動画

../../../_images/MasterJoinUpdate.gif

終わりに

という演算子の動作を可視化するツールを作った, という夢を見ました.

]]>
Tue, 01 Apr 2014 00:00:00 +0900
http://tink.elliptium.net/2014/03/30/kyon_mm_kaori_t_spica_wedding.html http://tink.elliptium.net/2014/03/30/kyon_mm_kaori_t_spica_wedding.html <![CDATA[kyon_mm * kaori_t_spica 結婚祝いLT大会 in Tokyo]]> kyon_mm * kaori_t_spica 結婚祝いLT大会 in Tokyo

という会に参加し, さらに発表までしてきました.

どんな会?

kyon_mm さんと kaori_t_spica さんのお二人のご結婚をきっかけとした LT 大会です. 私も発表者の一人として CPython の実装について話してきました.

イベントページ: http://peatix.com/event/29745

聞き手としての感想

技術的に深いネタや人生経験とそれに対する考察など面白い発表ばかりで, 刺激的なイベントでした. フリーテーマな LT だったので, 自分の知らない分野の話が聞けたのが良かったです. 頭の中にキーワードを残しておいて, 時間のあるときに調べようと思います.

発表内容

発表内容についてはスライドを参照してください. これを読むと, C でどんなふうに Python の型を実装しているかが (なんとなく) 分かると思います.

発表スライド: http://www.slideshare.net/cocoatomo/ss-32876382

公式の資料の 新しい型を定義する を読めば CPython の型についてだいぶ分かりそうですが, この文書はちょっと長過ぎるので, いつか別視点から実装の詳細についてまとめてみたいと思っています.

反響的には以下のページを見てください.

Togetter: http://togetter.com/li/648381?page=4 の 15:40 くらいから

はてブ: http://b.hatena.ne.jp/entry/www.slideshare.net/cocoatomo/ss-32876382

Twitter での検索結果: https://twitter.com/search?q=http%3A%2F%2Fwww.slideshare.net%2Fcocoatomo%2Fss-32876382&f=realtime

関係無い話ですが, はてブ数と「すべてのブックマーク」一覧の数がだいぶ違う気がするんですが気のせいでしょうかね?

発表者としての感想

実はこう見えても小さい頃から上がり性でして, 久々の勉強会での発表で緊張していて, そこにビールが入ったことでやや変なテンションになってました. 分かっていたことですが, モヒカンの巣窟で技術の発表するのは本当に緊張します.

その緊張からかスライドを表示させるときに操作を間違えて, 軍艦ネタのスライドを最初に見せてしまいました. まぁ, 失笑は起きなかったので大丈夫だったのでしょう.

初見で質問するには難しい内容だったかもしれませんが, それでもいくつか質問や指摘をいただいて, マサカリキャッチボール (「キャッチマサカリ」か?) をすることができたのは嬉しかったです. 傍目にどう映っていたかは分かりませんが, 私としては本当に心から楽しく議論をしていました. ただし, 今後きょんくんの前で発表するときには, 言葉の定義だけには気を付けようと思いました.

読者の宿題

面白そうだと思ったネタだったので, 資料の途中に「読者の宿題」として「実行」の定義を問う文を書きました. 発表の場ではさらっと答えを言い, きょんくんが頷いていたので伝わったと思っていますが, (私の) 答えが気になる人は Twitter とかで Mention ください.

おわりに

きょんくんがもっと東京に来るか, 自分がもっと名古屋に行けるようになって, 「○○基礎勉強会」的な勉強会にもっと出たいと思いました.

お二人が幾久しくお幸せでありますように.

それでは.

]]>
Sun, 30 Mar 2014 00:00:00 +0900
http://tink.elliptium.net/2014/03/22/use_javafx_from_jython_on_top_of_java_8.html http://tink.elliptium.net/2014/03/22/use_javafx_from_jython_on_top_of_java_8.html <![CDATA[use JavaFX from Jython on top of Java 8]]> use JavaFX from Jython on top of Java 8

Java 8 GA has released!

On March 18, 2014, Java 8 became GA. Simultaneously, the version number of JavaFX was raised upto 8 – JavaFX 8.

Preview

I wrote a blog post containing Jython scripts using JavaFX API. http://blog.elliptium.net/2012/12/use-JavaFX-from-Jython

Let’s retry these scripts with Java 8.

Retry

In order to re-compile Jython with Java 8, run folloing commands:

$ echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home

$ java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)

$ brew uninstall jython
Uninstalling /usr/local/Cellar/jython/2.5.3...

$ brew install jython
$ jython
*sys-package-mgr*: processing new jar, '/usr/local/Cellar/jython/2.5.3/libexec/jython.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/resources.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/rt.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/jsse.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/jce.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/charsets.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/jfr.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/cldrdata.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/dnsns.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/jfxrt.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/localedata.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/nashorn.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/sunec.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar'
*sys-package-mgr*: processing new jar, '/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib/ext/zipfs.jar'
*sys-package-mgr*: processing new jar, '/System/Library/Java/Extensions/MRJToolkit.jar'
*sys-package-mgr*: processing new jar, '/System/Library/Java/Extensions/QTJava.zip'
Jython 2.5.3 (2.5:c56500f08d34+, Aug 13 2012, 14:48:36)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0
Type "help", "copyright", "credits" or "license" for more information.
>>>

## OK

続きを読む...

]]>
Sat, 22 Mar 2014 00:00:00 +0900
http://tink.elliptium.net/2014/03/22/the_second_densei_sen.html http://tink.elliptium.net/2014/03/22/the_second_densei_sen.html <![CDATA[第 2 回電聖戦]]> 第 2 回電聖戦

2014 3/21 (金) 開催の「第 2 回電聖戦」の大盤解説を聴講してきました.

感想

そもそもプロ棋士を直接拝見するのも, 大盤解説を聞くのも初めてでワクワクしながら会場に向かいました. 会場は電気通信大学で, そこの伊藤研究室 (←表現が正確じゃないかも) と日本棋院が提携してこのイベントを開いているようです.

あ, そう言えば電通大に行ったのも初めてでした. 街の中にある大学, という感じで, 都会的でお洒落な印象を持ちました. 立看だらけだったり, 築70年くらいの寮があったり, すごく雑多だった出身大学を思うと,「綺麗だなぁ」という印象が強かったです. (聞くところによると, 今の時期は新歓の萌えな立看が並ぶという話もあり, 電聖戦のために移動したのかもしれません.)

会場は大学の大講義室で懐しい雰囲気を味わえました. 全部で 200 人くらい入れそうな部屋の後ろ 1/3 に放送機材などが設置され, 前 2/3 がほぼ人で埋まっていたので, 100 人超が現地で大盤解説を聞いたことになると思います. 現地以外にもニコ動の 竜星囲碁チャンネル で流れてたり, 5/25 (日) に 囲碁・将棋チャンネル でも放送されるそうです. そういう視聴者を入れるとどれくらいの人が観戦していたのでしょう? それなりに盛り上がったのではないでしょうか.

続きを読む...

]]>
Sat, 22 Mar 2014 00:00:00 +0900
http://tink.elliptium.net/2014/03/16/to_be_written.html http://tink.elliptium.net/2014/03/16/to_be_written.html <![CDATA[執筆予定記事]]> 執筆予定記事

書く予定のネタ達

どっかに書いておかないと忘れるので自分用メモ

  • TAPL の学習記録
    • 評価戦略
    • OOP の late-binding (Java の this とか)
  • Asakusa バッチを設計しているときに考えていること
    • まだ考え足りないこと
  • Asakusa Framework の演算子の動きを動画にしてみた
    • 動画を作るツールを作って記事にする
  • 勝手 Asakusa Framework Source Code Reading
    • 中身を詳細に知りたい
  • 11 の倍数に, 各桁の数字の和が偶数なものはいくつくらいあるのか?
    • 「11 の倍数は, 各桁の数字の和が偶数になる」という珍説の検証

ひとまずこんな感じ. 思い付いたら追加する.

公開しとかないと書かない気もしたので, 自分にプレッシャー掛けてみました.

]]>
Sun, 16 Mar 2014 00:00:00 +0900
http://tink.elliptium.net/2014/02/09/python_libraries_to_create_a_svg_file.html http://tink.elliptium.net/2014/02/09/python_libraries_to_create_a_svg_file.html <![CDATA[SVG ファイルを作成する Python ライブラリ]]> SVG ファイルを作成する Python ライブラリ

ちょっと訳あって, SVG ファイルを作成する Python ライブラリを調べています. PyPI から SVG で検索して見付かったライブラリを片っ端から調査していきます.

$ pip search SVG
pygal                     - A python svg graph plotting library
CairoSVG                  - A Simple SVG Converter for Cairo
svg.charts                - Python SVG Charting Library
Cnc25D                    - CAD library for 2.5D parts (including gears) using svgwrite, dxfwrite or FreeCAD as backend
gpml2svg                  - Render GPML pathway markup to SVG from the commandline/Python.
eea.converter             - SVG, PNG, PDF converters using external tools as ImageMagick
svgbatch                  - Loads SVG files into pyglet Batch objects for OpenGL rendering.
svgwrite                  - A Python library to create SVG drawings.
XStatic-svg-edit-moin     - svg-edit-moin 2012.11.27 (XStatic packaging standard)
pysvg                     - Python SVG Library
fullmarks.tinymceplugins.asciisvg - ASCIISvg Plugin for TinyMCE in Plone for drawing a graph of function in SVG
pydirstat                 - Show statistics informations for a directory in HTML, SVG, or Flash.
svgsitemap                - a site map using PyGraphviz and svg
glsvg                     - OpenGL SVG Renderer
sauvage                   - sauvage is a library that helps creating, manipulating and rendering SVG scenes with OpenGL
svglib                    - An experimental library for reading and converting SVG.
qrplatba                  - QR platba SVG QR code and SPAYD string generator
XStatic-svgweb            - svgweb 2011.2.3 (XStatic packaging standard)
pixel2svg                 - pixel2svg - Convert pixel art to SVG
scour                     - Scour SVG Optimizer
svg.path                  - SVG path objects and parser
PyQRCode                  - A QR code generator written purely in python 3 with SVG and PNG output.
simplesvg                 - UNKNOWN
nsi.svgtool               - UNKNOWN
Things                    - A vector animation API using Python, Cairo and Inkscape SVG files. Create quick animations by containment, keyframe tweening and other simple Things. New, one can
                            now export each frame as PNG or SVG files.
pytablefy                 - A python SVG table library
svgobject                 - Object-oriented library for handling SVG drawings
svglue                    - Create templates using Inkscape, then fill them in (and render them to PDF, if you like).
ewscal                    - Render Exchange calendars to SVG using d3.js
svgplotlib                - SVG plotting library
svg2rlg                   - Convert SVG to Reportlab drawing
svgutils                  - Python SVG editor
Charty                    - Another Python SVG Chart Generator that uses CSS smartly
django_svg                - SVG solution for all browsers. PNG versions of the SVG will be asynchrously generated by Batik and presented to browsers that do not support SVG.
collective.pygal.core     - Pygal dynamic SVG charting library integration for plone
pyWxSVG                   - SVG canvas for wxPython

の結果を調べてみた.

SVG ライブラリ
名称 対応 Python バージョン URL ライセンス コメント
(理想) Python 3 N/A オープンソース 開発が続いてること
pygal Python 2.6, 2.7, 3.2, 3.3 https://pypi.python.org/pypi/pygal, http://pygal.org LGPL v3 データを表示するためのものらしい.
CairoSVG Python 2.6, 2.7, 3.2, 3.3 https://pypi.python.org/pypi/CairoSVG, http://cairosvg.org LGPL v3 SVG を他の形式に変換するものらしい.
svg.charts Python 2.6, 2.7. 3 https://pypi.python.org/pypi/svg.charts, http://pythonhosted.org/svg.charts/ MIT グラフ描画用で目的が違う
Cnc25D ? https://pypi.python.org/pypi/Cnc25D/, http://pythonhosted.org/Cnc25D/ GPLv3 or later CNC 用で目的が違う
gpml2svg Python 2 https://pypi.python.org/pypi/gpml2svg/, http://www.genmapp.org BSD 遺伝子地図のなんとからしい. 目的が違い過ぎる
eea.converter ? https://pypi.python.org/pypi/eea.converter GPLv2 PDF を生成するものっぽい. Getting Started の PDF が localhost に置いてある.
svgbatch Python 2.5, 2.6 https://pypi.python.org/pypi/svgbatch BSD SVG ファイルを変換するもの.
svgwrite Python 2.7, 3.2, 3.3 https://pypi.python.org/pypi/svgwrite/, https://bitbucket.org/mozman/svgwrite MIT 求めていた SVG を作成するもの. 最近まで更新されてるので期待.
XStatic-svg-edit-moin ? https://pypi.python.org/pypi/XStatic-svg-edit-moin/2012.11.15.1, https://code.google.com/p/svg-edit/ (svg-edit-moin と一緒, なんのこっちゃ) svg-edit という JS のツールを MoinMoin で使えるようにしたもの (?)
pySVG Python 2.6 https://pypi.python.org/pypi/pysvg, http://codeboje.de/pysvg/ 2 Clause BSD ドキュメントが少なく, ここ最近メンテもされてない.
fullmarks.tinymceplugins.asciisvg ? https://pypi.python.org/pypi/fullmarks.tinymceplugins.asciisvg GPL 関数のグラフを描画するためのものらしい.
pydirstat ? https://pypi.python.org/pypi/pydirstat/0.9.15, http://pydirstat.berlios.de GPL ディレクトリごとの占有してる領域のサイズを SVG などで綺麗に表示してくれる. diskring や
svgsitemap ? https://pypi.python.org/pypi/svgsitemap, http://k0s.org/map.svg ? サイトマップを SVG で表示するもの
glsvg ? https://pypi.python.org/pypi/glsvg, https://github.com/fathat/glsvg Public Domain OpenGL を使って表示するらしい. SVG の読み書きができるらしい. Github の更新は最近無い.
sauvage ? https://pypi.python.org/pypi/sauvage, http://lii-enac.fr/~conversy/research/sauvage/ LGPL OpenGL を使って表示するらしい. サンプル画像とか載ってていい感じ. ただし, alpha 状態とのこと. PyPI にダウンロードリンクが無い!
svglib ? https://pypi.python.org/pypi/svglib/ LGPLv3 SVG を PDF に変換するもの. 残念. きちんと整備されている感じ. 最近の更新は無い.
qrplatba Python 2.7, 3.3 https://pypi.python.org/pypi/qrplatba MPL 2.0 QR コードを生成するためのもの.
XStatic-svgweb ? https://pypi.python.org/pypi/XStatic-svgweb, https://code.google.com/p/svgweb/ (svgweb と同じ) HTML に組み込んでブラウザ上で SVG を扱うもの. JS で動いてるらしい. 今回の目的とは違う.
pixel2svg Python 2.x https://pypi.python.org/pypi/pixel2svg, http://florian-berger.de/en/software/pixel2svg/ GPL ピクセル画像を SVG に変換するもの. もちろんピクセルのまま.
scour ? https://pypi.python.org/pypi/scour, http://www.codedread.com/scour/, https://github.com/oberstet/scour Apache 2.0 SVG を綺麗にしてファイルサイズを小さくするもの. scour = ゴシゴシ洗う
svg.path Python 2.6, 2.7, 3.1, 3.2, 3.3 https://pypi.python.org/pypi/svg.path, https://github.com/regebro/svg.path CC0 1.0 Universal 線 (path) しか引けないっぽい.
PyQRCode Python 3 https://pypi.python.org/pypi/PyQRCode, https://github.com/mnooner256/pyqrcode LGPLv3 名前の通り QR コードを生成するものらしい.
simplesvg ? https://pypi.python.org/pypi/simplesvg, https://github.com/forana/simplesvg ? pySVG と svgwrite では満足できないところがあって作ったらしい. 基本的な図形は描けそう.
nsi.svgtool ? https://pypi.python.org/pypi/nsi.svgtool GPL やる気が感じられない……
Things Python 2.5 https://pypi.python.org/pypi/Things, http://savannah.nongnu.org/projects/things/ GPL やりたいこととすごく合ってるのだが, どうももう更新されていないっぽい.
pytablefy ? https://pypi.python.org/pypi/pytablefy, https://github.com/fayizk1/pytablefy ? いまいち何ができるか分からない
svgobject ? https://pypi.python.org/pypi/svgobject GPL ドキュメントが少なくて何ができるかよく分からなかった.
svglue ? https://pypi.python.org/pypi/svglue MIT Inkscape と連携するもの? っぽい. 関係無さそう.
ewscal ? https://pypi.python.org/pypi/ewscal MIT d3.js とある辺りで関係無さそう.
svgplotlib ? https://pypi.python.org/pypi/svgplotlib, BSD グラフのプロットは目的ではない.
svg2rlg ? https://pypi.python.org/pypi/svg2rlg BSD SVG から別形式への変換なので関係無い.
svgutils Python 2.6, 2.7 https://pypi.python.org/pypi/svgutils, https://github.com/btel/svg_utils, http://neuroscience.telenczuk.pl/?p=331 MIT どうも SVG の結合の方を指向しているようで, 今回とは関係無い.
Charty ? https://pypi.python.org/pypi/Charty ? チャートが目的ではないので関係無い.
django_svg ? https://pypi.python.org/pypi/django_svg MIT SVG の代わりに PNG で表示するツールらしい.
collective.pygal.core Python 2 https://pypi.python.org/pypi/collective.pygal.core, https://github.com/collective/collective.pygal.core GPL pygal の Plone 版らしい.
pyWxSVG Python 2.5 https://pypi.python.org/pypi/pyWxSVG, http://shanto.ru (露語?) BSD wxPython 用なので関係無さそう.

色々調べてみて, 目的, できることが明示されていたり, デモ画像が見られるものは興味を惹かれますね. Python バージョンが明記してあるものは安心して使えます. ライセンスが明記してないと, どう仕様ライブラリのライセンスをどう処理していいか分からないので困ります.

結論としては, 任意の SVG ファイルを作成するなら svgwrite がほぼ唯一の選択肢のようです.

とりあえず SVG の調査はここまでとします.

]]>
Sun, 09 Feb 2014 00:00:00 +0900
http://tink.elliptium.net/2014/01/19/programming_languages_whose_logo_is_an_animal_of_chinese_astrology.html http://tink.elliptium.net/2014/01/19/programming_languages_whose_logo_is_an_animal_of_chinese_astrology.html <![CDATA[十二支のロゴを持つプログラミング言語]]> 十二支のロゴを持つプログラミング言語

ふと思い立って考えてみました. Twitter でつぶやいたところ, たくさんの情報をいただきありがとうございました.

その中でも Dog という言語は Esolang (the esoteric programming languages, 秘伝のプログラミング言語) なんて名前の Wiki に載せてあり, この Wiki の存在自体が知れて面白かったです.

Dog のページ → http://esolangs.org/wiki/DOG

情報をいただくたびに更新かけていたのですが, Twitter の 140 文字制限がきつくなってきたので, ブログ記事として書いておきます.

ロゴが干支の言語
干支 プログラミング言語
Squeak, Go
Guile, Bison, GCC
?
?
LLVM
Python
grass-mud-horse
C-Sheep
Zimbu
Coq
Dog
Grunt
Scratch

肝心の今年の干支「午」のロゴを持つプログラミング言語が見付かってません. もし知っていれば誰か教えてください. 寅と卯も募集中です.

それでは.

【追記 2014/01/20 00:05】

「午」に grass-mud-horse を追加

]]>
Sun, 19 Jan 2014 00:00:00 +0900
http://tink.elliptium.net/2014/01/15/pip_upgrade_with_a_requirements_txt.html http://tink.elliptium.net/2014/01/15/pip_upgrade_with_a_requirements_txt.html <![CDATA[requirements.txt を使って pip upgrade]]> requirements.txt を使って pip upgrade

pip について

pip コマンドは Python のライブラリの管理を行うツールです. Python 使ってる人なら少なくとも聞いたことくらいはあるでしょう.

pip については検索するとたくさん情報が出てくるので, それらを参照してください.

https://pypi.python.org/pypi/pip

ライブラリを一括更新

$ pip install --upgrade <library>

とやってライブラリを最新に上げるわけですが, pip freeze -l コマンドの結果を記録した requirements.txt を使う場合, 一緒にバージョン指定も付いているため最新になってくれません.

検索するとこんな情報が出てきて, どうやらライブラリ1つ1つに更新をかけていかないといけないようです.

requirements.txt はライブラリ名が列挙されているだけなので, ファイルの内容を上手く加工してやってみましょう.

$ awk 'BEGIN { FS = "==" } { print $1 }' requirements.txt | xargs pip install --upgrade

これで無事に全部のパッケージが更新できました.

おまけ

awk コマンドでの FS (field separator) の指定は, -F オプションでできるらしく指摘を受けました.

その指摘を反映して, 最終的にこんなコマンドになります.

$ awk -F "==" '{ print $1 }' requirements.txt | xargs pip install --upgrade

それでは.

]]>
Wed, 15 Jan 2014 00:00:00 +0900
http://tink.elliptium.net/2014/01/05/getting_start_with_proof_market.html http://tink.elliptium.net/2014/01/05/getting_start_with_proof_market.html <![CDATA[Getting start with Proof Market]]> Getting start with Proof Market

About Proof Market

Proof Market (https://proofmarket.org) is a web site for theorem providers and theorem provers. Theorem providers submit theorems to be proved with Coq and theorem provers offer their proofs with some price as bounty.

The currency used in this market is BitCoin. A BitCoin address and a amount of BitCoin money are needed when submitting a proof. To read the proof costs a specified amount of BitCoin money.

How to prove theorems and submit proofs

  1. Choose a theorem from Problem List.

  2. Make a directory for the problem.

  3. Copy contents from the Definitions section and save these as a file Definitions.v. Similarly, Answer.v from the Answer Template section, Verify.v from the Verifier section.

    As a Result, directory structure is shown as folloing:

    <Problem Name>/
      Answers.v
      Definitions.v
      Verify.v
    

    If there is no Definition section in the problem page, Definitions.v is not needed.

  4. Write a proof.

    If the last line of an Answer Template is “Admitted.” which means I have not completed the proof, you should change the line into “Qed.” which means I have completed the proof.

  5. Verify the proof.

    ## goto the problem directory
    $ cd <Problem Name>
    
    ## compile Definitions.v if exists
    $ coqc Definitions.v
    
    $ coqc Answer.v
    $ coqc Verify.v
    ## if Verify.v depends on Definitions.v, a require option is needed
    ## $ coqc -require Definitions Verify.v
    
    $ coqchk -o -norec Answer
    

Using ProofGeneral

At the process “4. Write a proof.”, you can use your favorite editors or IDEs. I use ProofGeneral (http://proofgeneral.inf.ed.ac.uk), because I love Emacs.

  1. Progress one step

    C-c C-n

  2. Progress steps until curser position

    C-c C-Enter

  3. Make compilation automatic

    If Verify.v depends on Definitions.v, it is convenient to enable automatic compilation.

    c.f. http://proofgeneral.inf.ed.ac.uk/htmlshow.php?title=Proof+General+user+manual+%28latest+release%29&file=releases%2FProofGeneral-latest%2Fdoc%2FProofGeneral%2FProofGeneral_12.html#Customizing-Coq-Multiple-File-Support

    From menu-bar, click Proof-General -> Advanced -> Customize -> Coq -> Coq Auto Compile -> Coq Compile Before Require....

Happy proving!!

]]>
Sun, 05 Jan 2014 00:00:00 +0900
http://tink.elliptium.net/2013/12/28/looking_back_on_2013_and_ambitions_for_2014.html http://tink.elliptium.net/2013/12/28/looking_back_on_2013_and_ambitions_for_2014.html <![CDATA[2013 年の振り返りと 2014 年の抱負]]> 2013 年の振り返りと 2014 年の抱負

ちょっと早いけど, 今年の振り返りと来年やりたい事を書いておきます.

今年の振り返り

今まではちょっとでも機会と興味があれば, 何かに飛び込んでいましたが, さすがにそろそろ時間的にも実績を積む面でもキツくなってきました.

社会人博士を中退する前後でも考えましたが, 後10年くらいの間でしたいことを絞って, それに向けて必要なことをしていかないと, 時間も体力も足りないことを実感しました. 昔よりは年を取ってるわけですし. (一応まだ若いのか??)

やりたいこと以外は手段と考えて, 随時, 取捨選択していきます.

2013 年の目標が Evernote に残っていたけど, やりたいことがてんこ盛り過ぎて大変そうでした. (他人事〜) 詰め込み過ぎずに, できることをできる分量だけやっていくことにします.

来年の抱負

  1. プログラミング

    1. 定理証明

      どうやったら現場で使えるか考えてみたいです (一般化テストケース, 仕様の記述かな?)

  2. 数学

    放っておくと頭が腐るので, ちょっとずつでも本読んで, 理解したことをブログに書いていこうかと思います.

  3. ブログ

    Asakusa Framework Advent Calendar 2013 でいくつか記事を書いたとき, 何かを考えたり学んだりしても, 形にして残さないと意味無いなーと思いました.

    数学で月に最低一本, プログラミング関連で月に最低一本は書こうと思います.

    しばらくは「TAPL の演習の回答とその思考過程の解説」とか「Asakusa Framework について」とかあれこれ書こうと思います.

]]>
Sat, 28 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/23/operator_decision_diagram.html http://tink.elliptium.net/2013/12/23/operator_decision_diagram.html <![CDATA[演算子選択のための流れ図]]> 演算子選択のための流れ図

この記事は Asakusa Framework Advent Calendar 2013 の23日目の記事として書いています. なお, この題材を選んだのは 昨日の hishidama さんの記事 が書かれるよりも前なのですが, 期せずして続き物のようになっています. 単なる偶然なので悪しからず.

Asakusa Framework にある DSL で一番細かいものが演算子です. Asakusa Framework では, 行える操作を演算子に制限することで様々な恩恵を受けています. 例えば, Hadoop バッチの設計のしやすさだったり, Ashigel コンパイラによる最適化だったり. その代償として「全ての処理を演算子で書かなければならない」という制限を受けます. 特に, 今したい処理に対してどの演算子を使えば良いかは, 最初は選択基準が分からず悩むと思います. (実際, 自分も悩みました)

参照: 演算子リファレンス http://docs.asakusafw.com/0.5.2/release/ja/html/dsl/operators.html

参照: Asakusa DSL の内部 http://www.slideshare.net/ashigeru/inside-of-asakusa-dsl

演算子一覧

そこで, 取っ掛かりの段階での演算子を選ぶヒントを表にまとめてみました.

https://www.icloud.com/iw/#numbers/BAL-GN_wp9y9gH1LgZWBQqpYTo06R-tO752E/%E6%BC%94%E7%AE%97%E5%AD%90%E4%B8%80%E8%A6%A7.numbers

続きを読む...

]]>
Mon, 23 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/21/deployments_and_build.html http://tink.elliptium.net/2013/12/21/deployments_and_build.html <![CDATA[デプロイとビルド]]> デプロイとビルド

この記事は Asakusa Framework Advent Calendar 2013 の21日目の記事として書いています.

前回が リリースとデプロイ だったので, 今回は運用側から開発側にもう1段階戻って「デプロイとビルド」について書きます.

Asakusa バッチのビルド

Asakusa バッチプロジェクトは長らく Maven を使って, ビルドの管理が行われてきました. そこに最近 Gradle が使えるようになりました. これらのツールが担ってきた役割を振り返ってみます.

  1. Asakusa バッチ開発環境の作成

    ${ASAKUSA_HOME} 以下に Asakusa バッチ開発環境を作成する. バッチのビルドで使用する.

  2. Eclipse 設定ファイルの生成

    .classpath, .settings などの Eclipse の設定ファイルを生成する. 後述の Asakusa によって自動生成される Java クラスへのパスもクラスパブに追加される.

  3. ExporterDescription/ImporterDescription, Operator Factory などの Java ソースコードの自動生成

    DMDL から生成されるモデルクラスや Exporter/Importer のクラス, 演算子を取得するときに使う Factory クラスの Java ソースコードを生成する

  4. Asakusa バッチアプリケーションのビルド

    batchapps.jar を作る

  5. Asakusa バッチ運用環境モジュールの作成

    リリース用のモジュールを作成する

続きを読む...

]]>
Sat, 21 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/17/releases_and_deployments.html http://tink.elliptium.net/2013/12/17/releases_and_deployments.html <![CDATA[リリースとデプロイ]]> リリースとデプロイ

この記事は Asakusa Framework Advent Calendar 2013 の 17 日目の記事として書いています.

Hadoop クラスタの選定と全体構成の検討と来て, 今回は実際にどんな構成で動かしていたか, バッチアプリケーションのリリースやデプロイはどう行っていたか, について (ぼやかしながら) 書きます. 関連した保守の話題なども含めてあります.

全体構成

リリースやデプロイの話をする前に, その対象となるシステムの構成について書きます. 構成については, 前回, 前々回の記事に基本的な考え方を書きましたので, 必要に応じて参照してください. → Asakusa バッチ実行環境の構成 (前編), Asakusa バッチ実行環境の構成 (後編)

クラスタは EMR を使っています. 当初 EMR が無かった頃は EC2 クラスタを使っていたのですが, なにぶんクラスタの操作を行うプログラムの保守工数がバカにならないので EMR に切り替えました.

続きを読む...

]]>
Tue, 17 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/14/structures_of_asakusa_batch_runtime_environments_part2.html http://tink.elliptium.net/2013/12/14/structures_of_asakusa_batch_runtime_environments_part2.html <![CDATA[Asakusa バッチ実行環境の構成 (後編)]]> Asakusa バッチ実行環境の構成 (後編)

この記事は Asakusa Framework Advent Calendar 2013 の 14 日目の記事として書いています.

今回の記事は以下のページを参考にしています. 用語などもここでの定義を使用しています. http://docs.asakusafw.com/0.5.2/release/ja/html/administration/deployment-with-windgate.html#id1

記事が長いので前編, 後編に分けています.

前編はこちら → Asakusa バッチ実行環境の構成 (前編)

ネットワークの考慮

前編の図2で黄色の線で書いた部分はマシンの外側のデータ転送経路を表しています. この部分はマシン内部のデータの移動に比べ, 速度や安定性の面で劣るので特別な考慮が必要です.

続きを読む...

]]>
Sat, 14 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/13/structures_of_asakusa_batch_runtime_environments_part1.html http://tink.elliptium.net/2013/12/13/structures_of_asakusa_batch_runtime_environments_part1.html <![CDATA[Asakusa バッチ実行環境の構成 (前編)]]> Asakusa バッチ実行環境の構成 (前編)

この記事は Asakusa Framework Advent Calendar 2013 の 13 日目の記事として書いています.

今回の記事は以下のページを参考にしています. 用語などもここでの定義を使用しています. http://docs.asakusafw.com/0.5.2/release/ja/html/administration/deployment-with-windgate.html#id1

記事が長いので前編, 後編に分けています.

後編はこちら → Asakusa バッチ実行環境の構成 (後編)

Asakusa バッチを実行するためのコンポーネント

Asakusa Framework を使ったバッチを実行するとき, 様々なコンポーネントが関連し合って一連の処理を動かしています. Asakusa バッチの本体は Hadoop ジョブの集まりですが, それだけではバッチとしては機能不足です. 実際にバッチとして動かすためには, ジョブ間の依存関係の管理や, ジョブ間で受け渡すデータの管理, 外部システムとの入出力を行う機能が必要になります. さらに, それらが分散配置されたときに全体を統括する機能も必要です.

Asakusa にはそれぞれの機能を担うコンポーネントが用意されており, それらを適宜組み合わせ構成します. それぞれのコンポーネントと組み合わせの特徴を掴み, 目的に合わせて構成するための指針を書いていきます. (あくまで自分の経験に基くもので, 所属する組織の公式見解ではありません. 念の為)

まずは, Asakusa バッチに登場するコンポーネントを分類しつつ並べていきます.

続きを読む...

]]>
Fri, 13 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/07/a_new_blog_theme.html http://tink.elliptium.net/2013/12/07/a_new_blog_theme.html <![CDATA[新しいブログテーマ]]> 新しいブログテーマ

sphinxjp.themes.tinkerbelizehole

Tinkerer のデフォルトテーマ flat があまり好みではなかったので, belizehole という名前の Sphinx テーマを適用してみました.

https://pypi.python.org/pypi/sphinxjp.themes.tinkerbelizehole/0.1.0

手順は以下の通りです. 実際には, virtualenv の環境を 1 つ専用に用意して作業してます.

$ python -V
Python 3.3.3
$ pip install sphinxjp.themes.tinkerbelizehole

## 必要なライブラリは以下の通り
$ pip freeze
...
Sphinx==1.2b3
...
Tinkerer==1.2.1
...
sphinxjp.themes.tinkerbelizehole==0.1.0
...

$ emacs conf.py
...
# Pick another Tinkerer theme or use your own
html_theme = "tinkerbelizehole"
...

## Sphinx 1.2 より前の場合は以下の行も編集する
# Add other Sphinx extensions here
extensions = [..., 'sphinxjp.themecore']
...

$ tinker -b

これで無事, 新しいテーマに切り替わりました.

PyPI のページには「Python 3 はサポートしていない」みたいに書いてありましたが, 普通に動きました. どうやら, このテーマの依存ライブラリ (これは Sphinx のテーマを自動で読み込むもの) である sphinxjp.themecore が Python 3 をサポートしていないために, このような記述があるようです. sphinxjp.themecore の作者の @shimizukawa さん聞いたら, 単に未検証だというだけだそうです. さらに, Sphinx 1.2b3 では既に本体に取り込まれているので, テーマだけインストールすれば html_theme の設定でテーマが適用されるそうです. すごいね.

このテーマはスマホ (私の場合は iPhone の Safari) で見ても, サイドバーが無く見やすいので気に入ってます. 作者は自称「プログラミングしょしんしゃ」の @naoiwata さんです.

]]>
Sat, 07 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/06/maintenance_and_operation_for_asakusa_batch.html http://tink.elliptium.net/2013/12/06/maintenance_and_operation_for_asakusa_batch.html <![CDATA[Asakusa バッチの保守と運用]]> Asakusa バッチの保守と運用

この記事は Asakusa Framework Advent Calendar 2013 の6日目の記事として書いています.

Asakusa Framework は Hadoop の上に位置するフレームワークで, Hadoop バッチをより設計しやすく, 保守しやすくするためのものです.

Asakusa Framework を使った開発については @hishidama さんの記事 (http://www.ne.jp/asahi/hishidama/home/tech/asakusafw/), 土佐鉄平 さんの記事 (http://teppei.hateblo.jp/search?q=asakusa), fullkawa さんの記事 (http://d.hatena.ne.jp/fullkawa/20120730/p1) があります. 開発についての記事はいくつかあるのですが, 保守についての記事はなかなか見ないです.

私は Asakusa バッチの開発に, Asakusa のバージョンが 0.2.6 (←確か) だった頃から関わっています. (フレームワークの方ではなくて, Asakusa Framework で作ったバッチの方です.) そこでは主に CI やテスト環境の整備, リリース管理, 運用のためのスクリプト作成をやっています. もちろんそれだけでは収まらなくて, バッチ書いたり, データの表示のための Web アプリを書いたりもしています. せっかくなので, ここらへんの保守やら運用やらの話について書いていこうと思います.

書く予定の内容

  1. Hadoop クラスタの準備

    社内か AWS (EC2 や EMR) か

  2. 全体構成について

    YAESS と WindGate の分散配置について

    Windows がある場合

    Asakusa バッチ実行環境の構成 (前編), Asakusa バッチ実行環境の構成 (後編)

  3. リリース, デプロイについて

    リリースとデプロイ

  4. デプロイとビルドについて

    デプロイとビルド

  5. ログについて

    EMR の新画面について

  6. 外部連携について

    速度計測計画中

今日は「1」の「Hadoop クラスタの準備」について書いていきます.

Hadoop クラスタの準備

Asakusa Framework は Hadoop クラスタ上で動作するフレームワークですので, まず Hadoop クラスタを用意しなければなりません. ではそのクラスタを動かす環境として, どんな候補があって, それらの選択の指針について書いていきます.

続きを読む...

]]>
Fri, 06 Dec 2013 00:00:00 +0900
http://tink.elliptium.net/2013/12/01/test.html http://tink.elliptium.net/2013/12/01/test.html <![CDATA[test]]> test

error

aaa

]]>
Sun, 01 Dec 2013 00:00:00 +0900