// quant1.C Version 7.44  Copyleft (c) 杉本典夫
// Time-stamp: <2025-11-01 09:28:02 tac>
//
// 最初の項目を目的変数Y、以後の項目を説明変数Xとした
// 重回帰分析+数量化理論I類。
//
// 使用ライブラリ:libdans.so, libfun.so
// コンパイル法 :g++ -O -s -W quant quant1.C
//             -I/usr/local/include -L/usr/local/lib -ldans -lfun

#include <dans.H>               // dans用ヘッダファイル(fun.H,mat.H含む)

using namespace dans;           // dans名前空間使用(名前空間matvec含む)

const vecstr USAGE =            // プログラム使用法表示用
{
  "quant1  Version 7.44         Copyleft(Vo\\oV) 2025 杉本典夫",
  "書式:quant1 [<オプション> …]  [<データファイル> …]",
  "機能:最初の項目を目的変数Yとし、以後の項目を説明変数Xとした",
  "     重回帰分析+数量化理論I類をするよ。",
  "<オプション>",
  "  -cc[=<信頼係数>]:信頼係数を指定するよ。(0≦信頼係数<1)",
  "    -cc:-cc=0.95(オプション省略時)",
  "  -f=<ファイル>:オプションを指定したファイルから読み込むよ。",
  "  -h[=<コマンド名>]:オンラインマニュアルを表示するよ。(-h:-h=man)",
  "  -res=[-][{def|all|reg|stat}][,…]:解析結果の出力項目を指定するよ。",
  "    -:-を付けた項目を出力しない(-res=-:全ての項目を出力しない)",
  "    def:オプション省略時と同じ項目を出力する  all:全ての項目を出力する",
  "    reg:回帰分析結果  stat:基礎統計量",
  "  -x<変数番号>=<コード1>,<コード2>[,<コード3>,…]:数量化する説明変数Xの",
  "    番号とコード内容を指定するよ。",
  "    コードを指定しない説明変数は計量値として集計するからね。"
};

const string Title = "=== 重回帰分析＋数量化理論I類 ==="; // 表題

using pairidat = pair<int, datac>; // 整数とデータクラスペアの別名定義

class option                    // オプションクラス
{
private:
  string v_path;                // プログラムのパス
  string v_pname;               // プログラム名
  double v_cc;                  // 信頼係数
  list<pairidat> quantlst;      // 数量化指定項目リスト
  vector<pairidat> quantvec;    // 数量化指定項目ベクトル
  lstr reslst;                  // 分析結果出力リスト
  mapsb resmap;                 // 分析結果出力の有無マップ
public:
  option(const char* c_pname = nullptr); // コンストラクタ
  ~option()                              // デストラクタ
  {}
  const string& path() const    // プログラムのパスを返す
  { return v_path; }
  const string& pname() const   // プログラム名を返す
  { return v_pname; }
  double cc() const             // 信頼係数を返す
  { return v_cc; }
  size_t quantlst_size() const  // 数量化指定項目リストのサイズを返す
  { return quantlst.size(); }
  const vector<pairidat>& quant() const // 数量化指定項目ベクトル
  { return quantvec; }
  int quant_ino(int idx) const  // 数量化指定項目番号を返す
  { return quantvec[idx].first; }
  size_t quant_n(int idx) const // 数量化指定項目のコード数を返す
  { return quantvec[idx].second.size(); }
  const string& quant_code(int iidx, int cidx) const // 数量化指定項目コードを返す
  { return quantvec[iidx].second.sdata(cidx); }
  int quant_search(int idx, const string& code) const;
  // 数量化指定項目コードをサーチしてインデックスを返す
  bool res(const string& code); // 結果出力フラッグを返す
  void setdef()                 // 省略時オプション指定を設定する
  { getoptdef(*this); }
  void set(const string& optstr, char devc = OPTdev);
  // オプション指定によってオプションを設定する
  int check(size_t ni);         // オプションのチェックとセット
  int set_res();                // -resオプションのセット
};

option::option(const char* c_pname) : v_path(), v_pname(), v_cc(CCdef), quantlst(), quantvec(), reslst(), resmap()
// コンストラクタ
{
  if (c_pname == nullptr) return; // 初期設定せず
  v_pname = getname(c_pname);     // パス名なしのプログラム名取得
  v_path = c_pname;
  strsize_t idx = v_path.find(v_pname);
  if (idx != string::npos) v_path.erase(idx); // プログラム名削除
}

bool option::res(const string& code) // 分析結果出力フラッグを返す
{
  mapsb_citr resitr = resmap.find(code);
  if (resitr == resmap.end()) return false; // code無し！
  return resmap[code];                      // true/falseを返す
}

void option::set(const string& optstr, char devc)
// オプション指定によってオプションを設定する
{
  string opt[2];                // オプションのopt[0]:項目,opt[1]:内容
  if (getopt(opt, optstr, devc) < 1) return; // オプション指定なし
  int err = 0;
  if (opt[0] == "cc")           // 信頼係数の指定
  {
    v_cc = opt[1].empty() ? CCdef : strtodf(opt[1]);
    if (v_cc < 0.0 || 1.0 <= v_cc) err = badopt(pname(), optstr, USAGE, 0.0, 1.0);
  }
  else if (opt[0] == "f")       // オプション指定ファイル
  { err = fgetopt(*this, opt[1], true); }
  else if (opt[0] == "h")       // オンラインヘルプ表示
  { err = help(pname(), USAGE, opt[1]); }
  else if (opt[0] == "res")     // 結果の出力指定
  {
    if (strsplit(reslst, opt[1], CHRdelm) < 1) err = badopt(pname(), optstr, USAGE);
  }
  else if (opt[0][0] == 'x')    // 数量化変数Xの指定
  {
    if (opt[1].empty())         // -xの時は数量化指定リスト削除
    { quantlst.clear(); }
    else
    {
      char* ptr = nullptr;
      int ino = strtol(opt[0].substr(1).c_str(), &ptr, 0);
      datac tdata;
      if (ino < 1 || tdata.getdata(opt[1]) < 2)
      { err = badopt(pname(), optstr, USAGE); }
      else
      { quantlst.push_back(make_pair(ino, tdata)); }
    }
  }
  else
  { err = nonopt(pname(), optstr, USAGE); }
  if (err > 0) throw help_except("ヘルプ表示");
  if (err < 0) throw option_error(string("オプション指定違反→") + optstr);
}

int option::check(size_t ni)    // オプションのセットとチェック
{
  if (ni < 2) return disperr(pname(), "項目が2つ以上必要だよ！");
  if (set_res() < 0) return -3; // -resオプションのエラー
  int nx = ni - 1;
  if ((int)(quantlst.size()) > nx) return disperr(pname(), "数量化項目が多すぎるよ！");
  quantvec.resize(nx);
  datac tdata;
  pairidat dummy(0, tdata);
  quantvec.assign(nx, dummy);
  if (quantlst.empty()) return nx; // 数量化項目指定なし
  int p = nx;                      // パラメータ数
  for (const auto& quanti : quantlst)
  {
    int idx = quanti.first - 1;
    if (idx < 0 || nx <= idx) return disperr(pname(), "数量化項目番号が不適だよ！");
    quantvec[idx] = quanti;  p += quanti.second.size() - 2;
  }
  return p;                     // ダミー変数も含めたパラメータ数を返す
}

int option::set_res()           // -resオプションのセット
{
  resmap["res"] = resmap["def"] = resmap["reg"] = resmap["stat"] = true;
  if (reslst.size() > 0)
  {
    resmap["def"] = resmap["reg"] = resmap["stat"] = false;
    for (const string& resstr : reslst)
    {
      mapsb_citr resitr = resmap.find(resstr);
      if (resstr == "-")        // 全て出力せず
      { resmap["res"] = false; }
      else if (resstr[0] == '-' && resstr.size() > 1) // 特定の項目を出力せず
      {
        resitr = resmap.find(resstr.substr(1));
        if (resitr == resmap.end())
        { return disperr(pname(), "-res=" + resstr + "オプション指定が不適切！"); }
        else
        { resmap[resstr.substr(1)] = false; }
      }
      else if (resstr == "def" || resstr == "all")
      { resmap["def"]= resmap["reg"] = resmap["stat"] = true; }
      else if (resitr == resmap.end())
      { return disperr(pname(), "-res=" + resstr + "オプション指定が不適切！"); }
      else
      { resmap[resstr] = true; }
    }
  }
  return 0;                     // エラーなし
}

int option::quant_search(int idx, const string& code) const
// 数量化指定項目コードをサーチしてインデックスを返す
{
  bool hit = false;
  int i = 0, n = quantvec[idx].second.size();
  while (hit == false && i < n)
  {
    if (code == quantvec[idx].second.sdata(i)) hit = true;
    else ++i;
  }
  return hit ? i : -1;          // -1:該当コードなし
}

class varclass                  // 変数クラス
{
private:
  mat<double> smat;             // 積和行列
  mat<double> xmat;             // 単純積和行列
  mat<double> v_qmat;           // 数量化行列
  mat<double> rmat;             // 相関行列
  vecdbl v_mevec;               // 平均値ベクトル
  vecdbl ssvec;                 // 積和ベクトル
  vecdbl v_vrvec;               // 分散ベクトル
  int v_ni;                     // 項目数
  int v_np;                     // パラメータ数
  int v_n;                      // 例数
  restype v_resvar;             // 処理結果の種類
  void set_quant(mat<double>& qmat, option& opt, const mat<double>& smat) const;
  // ダミー変数による単純積和行列を数量化変数による単純積和行列に変換する
  void cal_vif(mat<double>& rmat, const mat<double>& xmat) const;
  // VIFを計算する
public:
  varclass(size_t ni, int np) : smat(np + 1), xmat(np), v_qmat(np + 1), rmat(np), v_mevec(ni + 1, 0.0), ssvec(ni + 1, 0.0), v_vrvec(ni + 1, 0.0), v_ni(ni), v_np(np), v_n(0), v_resvar(resnon)
  // コンストラクタ
  {}
  ~varclass()                   // デストラクタ
  {}
  const mat<double>& qmat() const // 数量化行列を返す
  { return v_qmat; }
  const vecdbl& mevec() const   // 平均値ベクトルを返す
  { return v_mevec; }
  const vecdbl& vrvec() const   // 分散ベクトルを返す
  { return v_vrvec; }
  int ni() const                // 項目数を返す
  { return v_ni; }
  int nx() const                // 説明変数の数を返す
  { return ni() - 1; }
  int np() const                // パラメータ数を返す
  { return v_np; }
  int n() const                 // 例数を返す
  { return v_n; }
  int dft() const               // 全自由度を返す
  { return n() - 1; }
  int dfb() const               // 回帰自由度を返す
  { return np() - 1; }
  int dfr() const               // 残差自由度を返す
  { return dft() - dfb(); }
  double w(int idx) const       // 数量化の重みを返す
  { return (0 <= idx && idx <= np()) ? smat(idx, np()) : 0.0; }
  double sxx(int idx) const     // 説明変数の積和を返す
  { return (0 <= idx && idx <= ni()) ? ssvec[idx] : 0.0; }
  double syy() const            // 目的変数の積和を返す
  { return ssvec[ni()]; }
  double sr() const             // 残差積和を返す
  { return v_qmat(ni(), ni()); }
  double sb() const             // 回帰積和を返す
  { return syy() - sr(); }
  double vr() const             // 残差分散を返す
  { return (dfr() > 0) ? sr() / dfr() : 0.0; }
  double b(int idx) const       // 偏回帰係数を返す
  { return (0 <= idx && idx < ni()) ? v_qmat(idx, ni()) : 0.0; }
  double vb(int idx) const      // 説明変数の分散を返す
  { return (0 <= idx && idx < ni()) ? vr() * v_qmat(idx, idx) : 0.0; }
  double bst(int idx) const     // 標準偏回帰係数を返す
  { return (0 <= idx && idx < ni()) ? b(idx) * sqrt(sxx(idx) / syy()) : 0.0; }
  double rp(int idx) const;     // 偏相関係数を返す
  double vif(int idx) const     // VIFを返す
  { return (0 < idx && idx < ni()) ? rmat(idx, idx) : 0.0; }
  restype resvar() const        // 処理結果の種類を返す
  { return v_resvar; }
  void cal(option& opt, ldata& datalst); // データを集計して各種統計量を求める
  void qreg();                  // 数量化した重回帰式を計算する
};

double varclass::rp(int idx) const // 偏相関係数を返す
{
  if (idx < 0 || idx >= ni()) return 0.0;
  double bi = b(idx);
  double v = sr() * v_qmat(idx, idx) + bi * bi;
  return (v > 0.0) ? bi / sqrt(v) : 0.0;
}

void varclass::cal(option& opt, ldata& datalst)
// データを集計して各種統計量を求める
{
  int dim = np() + 1;
  vecdbl fdatavec(dim, 0.0);
  fdatavec[0] = 1.0;
  for (auto& cdatai : datalst)
  {
    bool blank = false;
    int i = 1;
    for (int j = 1; blank == false && j < ni(); ++j)
    {
      if (opt.quant_ino(j - 1) < 1) // 計量値項目
      {
        fdatavec[i] = cdatai.fdata(j);
        if (fdatavec[i] == BLANKf) blank = true;
        else ++i;
      }
      else
      {
        int idx = opt.quant_search(j - 1, cdatai.sdata(j));
        if (idx < 0)            // 該当コードがない時は欠損扱い
        { blank = true; }
        else
        {
          int nd = opt.quant_n(j - 1) - 1;
          for (int k = 0; k < nd; ++k) fdatavec[i + k] = 0.0;
          if (idx > 0) fdatavec[i + idx - 1] = 1.0;
          i += nd;
        }
      }
    }
    if (cdatai.fdata(0) != BLANKf && blank == false)
    {
      fdatavec[np()] = cdatai.fdata(0);
      for (int i = 0; i < dim; ++i)
      {
        double x = fdatavec[i];
        for (int j = i; j < dim; ++j) smat.add(i, j, x * fdatavec[j]);
      }
    }
  }
  v_n = (int)(smat(0, 0));
  v_qmat = smat;
  for (int i = 0; i < np(); ++i)
  {
    for (int j = i + 1; j <= np(); ++j) smat.assign(j, i, smat(i, j));
  }
  for (int i = 0; i < np(); ++i) smat.sweep(i);
  set_quant(v_qmat, opt, smat);
  for (int i = 0; i < np(); ++i)
  {
    xmat.assign(i, i, v_qmat(i, i));
    for (int j = i + 1; j <= np(); ++j)
    {
      v_qmat.assign(j, i, v_qmat(i, j));
      if (j < np())
      {
        xmat.assign(i, j, v_qmat(i, j));  xmat.assign(j, i, v_qmat(i, j));
      }
    }
  }
  v_qmat.sweep(0);
  for (int i = 0; i <= ni(); ++i)
  {
    v_mevec[i] = v_qmat(0, i);
    ssvec[i] = v_qmat(i, i);
    if (ssvec[i] < FDeps) ssvec[i] = 0.0;
    v_vrvec[i] = (v_n > 1) ? ssvec[i] / (double)(v_n - 1) : 0.0;
  }
  if (v_n < np() || ssvec[ni()] <= 0.0) v_resvar = reserr;
  else v_resvar = resok;
}

void varclass::set_quant(mat<double>& qmat, option& opt, const mat<double>& smat) const
// ダミー変数による単純積和行列を数量化変数による単純積和行列に変換する
{
  if (opt.quantlst_size() < 1) return; // 数量化指定変数なし
  int is = 1;
  for (int i = 1; i < ni(); ++i)
  {
    if (opt.quant_ino(i - 1) < 1) // 計量値項目
    { ++is; }
    else
    {
      int ie = is + opt.quant_n(i - 1) - 1;
      double xy = 0.0;
      for (int k = 0; k < is; ++k)
      {
        xy = 0.0;
        for (int j = is; j < ie; ++j) xy += smat(j, np()) * qmat(k, j);
        qmat.assign(k, is, xy);
      }
      xy = 0.0;
      for (int k = is; k < ie; ++k) xy += smat(k, np()) * smat(k, np()) * qmat(k, k);
      qmat.assign(is, is, xy);
      for (int j = ie; j <= np(); ++j)
      {
        xy = 0.0;
        for (int k = is; k < ie; ++k) xy += smat(k, np()) * qmat(k, j);
        qmat.assign(is, j, xy);
      }
      is = ie;
    }
  }
  is = 0;
  for (int i = 0; i <= ni(); ++i)
  {
    int nd = (i == 0 || i == ni() || opt.quant_ino(i - 1) < 1) ? 1 : opt.quant_n(i - 1) - 1;
    qmat.assign(i, i, qmat(is, is));
    int k = is + nd;
    for (int j = i + 1; j <= ni(); ++j)
    {
      qmat.assign(i, j, qmat(is, k));
      k += (j == ni() || opt.quant_ino(j - 1) < 1) ? 1 : opt.quant_n(j - 1) - 1;
    }
    is += nd;
  }
}

void varclass::qreg()           // 数量化重回帰式を計算する
{
  for (int i = 1; i < ni(); ++i) v_qmat.sweep(i); // 重回帰式計算
  rmat.assign(0, 0, xmat(0, 0));
  for (int j = 1; j < np(); ++j)
  {
    rmat.assign(0, j, xmat(0, j));  rmat.assign(j, 0, xmat(0, j));
  }
  for (int i = 1; i < np(); ++i)
  {
    rmat.assign(i, i, xmat(i, i));
    for (int j = 1; j < np(); ++j)
    {
      rmat.assign(i, j, xmat(i, j));  rmat.assign(j, i, xmat(i, j));
    }
  }
  rmat.sweep(0);                // 積和行列にする
  smat2rmat(rmat);              // 相関行列にする
  mat<double> tmat(rmat.sub(1, 1, np() - 1, np() - 1));
  tmat.inv();                   // 相関行列部分を逆行列にする
  for (int i = 0; i < np() - 1; ++i)
  {
    for (int j = 0; j < np() - 1; ++j) rmat.assign(1 + i, 1 + j, tmat(i, j));
  }
}

class quant1class               // quant1メインクラス
{
private:
  string fname;                 // ファイル名
  idd id;                       // データ識別情報
  ldata datalst;                // データリスト
  void put_resid(ostream& fout); // 解析結果のタイトルとデータ識別情報を出力する
  void put_weight(ostream& fout, option& opt, const varclass& var) const;
  // 数量化変数の重みを出力する
  void put_rtab(ostream& fout, option& opt, const varclass& var) const;
  // 重回帰分析+数量化理論I類の結果を出力する
  void put_qbci(ostream& fout, option& opt, const varclass& var) const;
  // 偏回帰係数の信頼区間を出力する
public:
  quant1class() : fname(), id(), datalst() // コンストラクタ
  {}
  ~quant1class()                // デストラクタ
  {}
  int get(const char* c_fname, option& opt); // データを読み込み累積する
  void put(option& opt);                     // 集計結果を出力する
};

void quant1class::put_resid(ostream& fout)
// 解析結果のタイトルとデータ識別情報を出力する
{
  puttitle(fout, Title);
  fout << "\n";
  id.put_title(fout);
  id.put_stra(fout);
  fout << "目的変数y   :" << id.item(0) << "\n";
  for (size_t i = 1; i < id.ni(); ++i)
  { fout << "説明変数x" << setw(3) << i << ":" << id.item(i) << "\n"; }
}

void quant1class::put_weight(ostream& fout, option& opt, const varclass& var) const
// 数量化変数の重みを出力する
{
  if (opt.quantlst_size() < 1) return; // 数量化指定変数なし
  fout << "\n・数量化変数の重み\n";
  for (int i = 0, k = 1; i < var.nx(); ++i)
  {
    if (opt.quant_ino(i) < 1)
    { ++k; }
    else
    {
      fout << "  x" << setw(3) << i + 1;
      fout << ":" << opt.quant_code(i, 0) << "=0";
      for (size_t j = 1; j < opt.quant_n(i); ++j, ++k)
      { fout << " " << opt.quant_code(i, j) << "=" << var.w(k); }
      fout << "\n";
    }
  }
}

void quant1class::put_rtab(ostream& fout, option& opt, const varclass& var) const
// 重回帰分析+数量化理論I類の結果を出力する
{
  fout << "\n・重回帰分析+数量化理論I類の結果\n";
  fout << "                     標準                                          有意確率\n";
  fout << "変数  偏回帰係数  偏回帰係数  偏相関係数        VIF       偏F値       p値\n";
  constexpr int LENline = 78;   // 区切り線の長さ
  putline(fout, LENline);
  double bi = var.b(0), vbi = var.vb(0);
  double fi = (vbi > 0.0) ? bi * bi / vbi : 0.0;
  ldbl pr = ftop(fi, 1, var.dfr());
  fout << "切片" << setw(12) << bi << setw(35) << "";
  fout << setw(12) << fi << setw(12) << pr << pind(pr) << "\n";
  for (int i = 1; i <= var.nx(); ++i)
  {
    bi = var.b(i);  vbi = var.vb(i);
    int df = (opt.quant_ino(i - 1) < 1) ? 1 : opt.quant_n(i - 1) - 1;
    fi = (vbi > 0.0 && df > 0) ? bi * bi / vbi / df : 0.0;
    pr = ftop(fi, df, var.dfr());
    fout << "x" << setw(3) << i << setw(12) << bi << setw(12) << var.bst(i);
    fout << setw(12) << var.rp(i) << setw(11) << var.vif(i);
    fout << setw(12) << fi << setw(12) << pr << pind(pr) << "\n";
  }
  putline(fout, LENline);
  put_qbci(fout, opt, var);
  double r2 = var.sb() / var.syy();
  double r2a = fabs(1.0 - var.vr() * (double)(var.dft()) / var.syy());
  double aic = (double)(var.n()) * log(var.sr() / (double)(var.n())) + (double)(2 * (var.np() + 1));
  fout << "重寄与率(決定係数)R2乗=" << r2;
  fout << "  自由度調整済重寄与率(決定係数)R'2乗=" << r2a << "\n";
  fout << "重相関係数        R   =" << sqrt(r2);
  fout << "  自由度調整済重相関係数        R'   =" << sqrt(r2a) << "\n";
  fout << "AIC(赤池の情報量基準)=" << aic << "\n\n";
  putatab(fout, "回帰", var.sb(), var.dfb(), var.sr(), var.dfr(), var.syy(), var.dft());
}

void quant1class::put_qbci(ostream& fout, option& opt, const varclass& var) const
// 偏回帰係数の信頼区間を出力する
{
  fout << "\n変数    偏回帰係数      標準誤差" << setw(5) << opt.cc() * 100.0;
  fout << "%絶対精度  信頼区間下限  信頼区間上限\n";
  constexpr int LENline = 74;   // 区切り線の長さ
  putline(fout, LENline);
  double bi = var.b(0), vbi = var.vb(0);
  double ci = calmcci(mcfis, opt.cc(), 1, 1, var.dfr(), 1, vbi);
  fout << "切片" << setw(14) << bi << setw(14) << sqrt(vbi);
  fout << setw(14) << ci << setw(14) << bi - ci;
  fout << setw(14) << bi + ci << "\n";
  for (int i = 1; i <= var.nx(); ++i)
  {
    int df = (opt.quant_ino(i - 1) < 1) ? 1 : opt.quant_n(i - 1) - 1;
    bi = var.b(i);  vbi = var.vb(i);
    ci = calmcci(mcfis, opt.cc(), 1, df, var.dfr(), 1, vbi);
    fout << "x" << setw(3) << i << setw(14) << bi;
    fout << setw(14) << sqrt(vbi) << setw(14) << ci;
    fout << setw(14) << bi - ci << setw(14) << bi + ci << "\n";
  }
  putline(fout, LENline);
}

int quant1class::get(const char* c_fname, option& opt)
// データを読み込み保存・累積する
{
  if (c_fname == nullptr) fname.erase();
  else fname = c_fname;
  int nc = fgetdata(fname, id, datalst);
  if (nc < 0) throw runtime_error("実行時エラー！");
  return nc;
}

void quant1class::put(option& opt) // 集計結果を出力する
{
  int p = opt.check(id.ni());
  if (p < 0 || opt.res("res") == false) return;
  varclass var(id.ni(), p + 1); // 変数オブジェクト
  var.cal(opt, datalst);        // 各種の計算実行
  put_resid(cout);
  if (opt.res("stat"))
  {
    putmsdvec(cout, var.n(), var.mevec(), var.vrvec(), var.nx(), 1);
    putmat(cout, "・相関行列(correlation coefficient matrix)", matr, var.n(), var.qmat(), var.nx(), 1);
  }
  if (var.resvar() == reserr)
  { cout << "※回帰式計算不可能！\n"; }
  else
  {
    var.qreg();                 // 数量化重回帰式計算
    put_weight(cout, opt, var);
    if (opt.res("reg")) put_rtab(cout, opt, var);
  }
  cout << "\n" << endl;
}

int main(int argc, char* argv[]) // メインルーチン
{
  quant1class quant1;           // メインクラス変数
  option opt(argv[0]);          // オプション
  try
  {
    opt.setdef();               // オプションの初期設定
    bool fok = true;            // ファイル処理フラッグ
    for (int i = 1; i <= argc; ++i)
    {
      if (i >= argc)
      {
        if (fok) quant1.get(nullptr, opt); // 標準入力から読み込む
      }
      else if (*(argv[i]) == CHRopt)
      { opt.set(argv[i] + 1);  fok = true; }
      else
      { quant1.get(argv[i], opt);  fok = false; }
    }
    quant1.put(opt);
  }
  catch (help_except& helpex)   // ヘルプファイル表示
  { return 0; }
  catch (option_error& opterr)  // オプション指定エラー
  { return 1; }
  catch (runtime_error& rterr)  // 実行時エラー
  {
    disperr(opt.pname(), rterr.what());
    return 2;
  }
  catch (...)                   // 予期せぬ例外
  {
    disperr(opt.pname(), "内容不明なエラー発生！");
    return 255;
  }
  return 0;
}
