commit 79f165d0930b56a7dc09585f38b3f3a44f54893b
parent b6373106e21e21df0c9a6ee4944cc5617432d82e
Author: minerva-jupiter <ryouturn@gmail.com>
Date: Thu, 4 Dec 2025 07:00:27 +0900
init
Diffstat:
24 files changed, 1406 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,5 @@
+.env*
+.venv
+llama-*
+mistral_typst_*
+__*
diff --git a/.gitmodules b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "vendor/llama.cpp"]
+ path = vendor/llama.cpp
+ url = https://github.com/ggerganov/llama.cpp.git
diff --git a/README.md b/README.md
@@ -0,0 +1,54 @@
+# Prepare Python
+## create venv
+### install uv
+`pip install uv`
+### create .venv
+`uv venv .venv`
+## activate venv
+`source .venv/bin/activate`
+if you use windows powershell, use `.\.venv\Scripts\activate.ps1`
+
+## install requirements
+`uv pip install -r requirements.txt`
+
+## setting for cuda
+please make sure you have cuda installed and set the environment variable CUDA_HOME to the path of your cuda installation.
+check for it can do with `nvcc --version`
+and install pytorch for your cuda version.
+for example nvcc version is 13.0
+`uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu130 --reinstall`
+And then, check this python env can use cuda with `python gpu_check.py`
+
+## set API key for gemini(only need to use structuring-training-data)
+`export GEMINI_API_KEY=your_api_key`
+if you use windows powershell, use `$env:GEMINI_API_KEY="あなたのAPIキー"`
+
+# Prepare Feedback
+you only need to use `python structuring-training-data.py`
+
+# integrate data
+integrate feedback and report's typst
+use `integrate_data.py`
+
+# training model
+use `train.py`
+it may cost many time.
+My RTX 3060 spend 10min.
+
+# convert model to gguf
+```
+python vendor/llama.cpp/convert_hf_to_gguf.py mistral_typst_merged --outfile mistral_typst_merged.f16.gguf --outtype f16
+```
+# quantize model
+```
+python quantize_gguf.py mistral_typst_merged.f16.gguf mistral_typst_merged.q4_0.gguf --quantize-fn q4_0
+```
+なおこのプログラムにはllama.cppのビルド済みバイナリが配置されているので動作している.
+必要に応じて最新のビルド済みバイナリに更新したり,自分でビルドしてください.
+
+# サーバーの起動
+```
+uvicorn api_server:app --host 0.0.0.0 --port 8080
+```
+サーバーがcudaを使わないときは,これを参考にしましたが,治りません.dll地獄です.
+https://zenn.dev/hellohazime/articles/ccd01c2df0b5c3
diff --git a/api_server.py b/api_server.py
@@ -0,0 +1,114 @@
+import json
+import os
+
+import torch
+import uvicorn
+from fastapi import FastAPI
+from llama_cpp import Llama
+from pydantic import BaseModel
+
+# --- 設定 ---
+MODEL_PATH = "mistral_typst_quantized.gguf"
+N_GPU_LAYERS = 999
+
+
+# --- FastAPI/Pydantic モデル ---
+class TypstInput(BaseModel):
+ typst_code: str
+
+
+class FeedbackItem(BaseModel):
+ type: str
+ location: str
+ text: str
+
+
+class FeedbackResponse(BaseModel):
+ feedback: list[FeedbackItem]
+
+
+# --- アプリケーションの初期化 ---
+app = FastAPI(title="Typst Feedback Review API")
+llm = None
+
+
+@app.on_event("startup")
+async def load_model():
+ global llm
+
+ if not os.path.exists(MODEL_PATH):
+ raise FileNotFoundError(f"GGUFファイルが見つかりません: {MODEL_PATH}")
+
+ print(f"モデル {MODEL_PATH} をロード中...")
+
+ try:
+ llm = Llama(
+ model_path=MODEL_PATH,
+ n_gpu_layers=N_GPU_LAYERS,
+ n_ctx=16384,
+ verbose=False,
+ )
+ print("モデルロード完了。推論はGPUで行われます。")
+
+ except Exception as e:
+ print(f"モデルロード中にエラーが発生しました: {e}")
+ llm = None
+
+
+@app.post("/api/feedback", response_model=FeedbackResponse)
+async def get_feedback(input_data: TypstInput):
+ if llm is None:
+ return {
+ "feedback": [
+ {
+ "type": "error",
+ "location": "System",
+ "text": "モデルがロードされていません。",
+ }
+ ]
+ }
+
+ prompt = f"[INST]\n以下のTypstコードのレビューを行い、文書のフォーマット、論理、文法に関する指摘事項を、JSON形式のリストとして出力してください。\n\nTypstコード:\n---\n{input_data.typst_code}\n---\n\nJSON形式の指摘リスト:\n[/INST]"
+
+ output = llm.create_completion(
+ prompt,
+ max_tokens=8192,
+ temperature=0.0,
+ stop=["[/INST]", "```"],
+ stream=False,
+ )
+
+ generated_text = output["choices"][0]["text"].strip()
+
+ print(generated_text)
+
+ try:
+ start_index = generated_text.find("[")
+ end_index = generated_text.rfind("]")
+
+ if start_index == -1 or end_index == -1:
+ raise ValueError(
+ "生成テキストに有効なJSON配列の開始/終了記号が見つかりません。"
+ )
+
+ json_string = generated_text[start_index : end_index + 1]
+ feedback_list = json.loads(json_string)
+
+ return FeedbackResponse(feedback=feedback_list)
+
+ except (json.JSONDecodeError, ValueError, IndexError) as e:
+ print(f"JSONパースエラーまたは抽出エラー: {e}")
+ return FeedbackResponse(
+ feedback=[
+ {
+ "type": "parse_error",
+ "location": "Output",
+ "text": f"モデルが出力したJSONのパースに失敗しました。生出力: {generated_text[:200]}...",
+ }
+ ]
+ )
+
+
+# --- サーバー起動 ---
+if __name__ == "__main__":
+ uvicorn.run("api_server:app", host="0.0.0.0", port=8080, reload=False)
diff --git a/api_test.py b/api_test.py
@@ -0,0 +1,49 @@
+import json
+import os
+
+import requests
+
+# FastAPIサーバーのエンドポイントURL
+url = "http://127.0.0.1:8080/api/feedback"
+# 読み込むファイル名
+file_path = "tran.typ"
+
+# ファイルが存在することを確認してから読み込む
+if not os.path.exists(file_path):
+ print(f"エラー: 指定されたファイル '{file_path}' が見つかりません。")
+ exit(1)
+
+try:
+ with open(file_path, "r", encoding="utf-8") as f:
+ # ファイルの内容を全て読み込む
+ typst_content = f.read()
+
+ # 送信するデータ(JSON形式のPython辞書)
+ # サーバーは 'typst_code' の値として実際のコード内容を期待しています
+ payload = {
+ "typst_code": typst_content,
+ }
+
+ print(f"POSTリクエストを {url} に送信中...")
+ print(f"--- ファイル内容の先頭をプレビュー ---")
+ print(typst_content[:100] + "...")
+
+ # POSTリクエストの実行
+ response = requests.post(url, json=payload)
+ print("postリクエストの実行が終わりました.")
+
+ # 応答ステータスコードの確認
+ response.raise_for_status()
+
+ print("--- 応答 ---")
+ print(f"ステータスコード: {response.status_code}")
+
+ # 応答JSONの表示
+ feedback_data = response.json()
+ print("応答JSONデータ:")
+ print(json.dumps(feedback_data, indent=2, ensure_ascii=False))
+
+except requests.exceptions.RequestException as e:
+ print(f"リクエスト中にエラーが発生しました: {e}")
+except Exception as e:
+ print(f"ファイル処理中にエラーが発生しました: {e}")
diff --git a/gpu_check.py b/gpu_check.py
@@ -0,0 +1,25 @@
+import torch
+
+# 1. CUDAが利用可能か(CUDA版PyTorchがインストールされているか)
+is_available = torch.cuda.is_available()
+print(f"torch.cuda.is_available(): {is_available}")
+
+if is_available:
+ # 2. PCに認識されているGPUの数
+ device_count = torch.cuda.device_count()
+ print(f"torch.cuda.device_count(): {device_count}")
+
+ # 3. 現在使用中のGPUの名前(通常0番目のGPU)
+ device_name = torch.cuda.get_device_name(0)
+ print(f"GPU Name: {device_name}")
+
+ # 4. GPU上でテンソル演算を実行できるか
+ try:
+ # GPU (CUDA) デバイスを指定
+ device = torch.device("cuda")
+ # テンソルをGPUメモリに作成し、演算を実行
+ tensor_on_gpu = torch.rand(2, 3, device=device)
+ print("\nSuccessfully created and calculated a tensor on GPU:")
+ print(tensor_on_gpu)
+ except Exception as e:
+ print(f"\nError accessing GPU for calculation: {e}")
diff --git a/integrate_data.py b/integrate_data.py
@@ -0,0 +1,89 @@
+import json
+import os
+from typing import Any, Dict, List
+
+
+def integrate_and_format_data(data_pairs: List[Dict[str, str]], output_file_path: str):
+ """
+ Typstファイルと構造化JSONファイルを統合し、学習用のJSON Lines形式に変換する。
+
+ Args:
+ data_pairs: TypstファイルパスとJSONファイルパスの辞書のリスト。
+ output_file_path: 出力するJSON Linesファイルパス。
+ """
+
+ formatted_data = []
+
+ for pair in data_pairs:
+ typst_path = pair["typst_file"]
+ json_path = pair["json_file"]
+
+ if not os.path.exists(typst_path) or not os.path.exists(json_path):
+ print(
+ f"警告: ファイルペアが見つかりません - Typst: {typst_path}, JSON: {json_path}"
+ )
+ continue
+
+ try:
+ # 1. Typstファイルの内容を読み込む
+ with open(typst_path, "r", encoding="utf-8") as f:
+ typst_content = f.read()
+
+ # 2. 構造化されたJSONのフィードバックリストを読み込む
+ with open(json_path, "r", encoding="utf-8") as f:
+ feedback_items = json.load(f)
+
+ # 3. フィードバックリストをJSON文字列に変換(LLMの出力形式として利用)
+ # 改行やスペースを除去し、整形された単一のJSON文字列にする
+ feedback_output = json.dumps(
+ feedback_items, ensure_ascii=False, separators=(",", ":")
+ )
+
+ # 4. LLM学習用のInstruction/Outputペアを作成
+ # Instruction: 入力となるTypstコード
+ # Output: 正解となる構造化フィードバックJSON
+ learning_example = {"instruction": typst_content, "output": feedback_output}
+
+ formatted_data.append(learning_example)
+ print(f"統合完了: {typst_path} と {json_path}")
+
+ except Exception as e:
+ print(f"エラー処理: {typst_path} / {json_path} - {e}")
+
+ # 5. すべてのデータをJSON Lines形式でファイルに書き出す
+ with open(output_file_path, "w", encoding="utf-8") as outfile:
+ for entry in formatted_data:
+ json.dump(entry, outfile, ensure_ascii=False)
+ outfile.write("\n")
+
+ print("\n--- 処理完了 ---")
+ print(
+ f"合計 {len(formatted_data)} 件の学習データが {output_file_path} に出力されました。"
+ )
+
+
+if __name__ == "__main__":
+ # === 設定箇所 ===
+
+ # 3回分のレポートとフィードバックのファイル名を指定してください
+ # (例: report_001.typ と structured_data_001.json のペア)
+ FILE_PAIRS = [
+ {
+ "typst_file": "reports/imp.typ",
+ "json_file": "structured-feedback/structured_data_001.json",
+ },
+ {
+ "typst_file": "reports/diff.typ",
+ "json_file": "structured-feedback/structured_data_002.json",
+ },
+ {
+ "typst_file": "reports/new.typ",
+ "json_file": "structured-feedback/structured_data_003.json",
+ },
+ # 必要に応じてさらにペアを追加
+ ]
+
+ OUTPUT_FILE_NAME = "typst_feedback_dataset.jsonl"
+
+ # === スクリプト実行 ===
+ integrate_and_format_data(FILE_PAIRS, OUTPUT_FILE_NAME)
diff --git a/quantize_gguf.py b/quantize_gguf.py
@@ -0,0 +1,43 @@
+import os
+import subprocess
+
+# --- 設定 ---
+INPUT_GGUF = "mistral_typst_merged.f16.gguf"
+OUTPUT_GGUF = "mistral_typst_quantized.gguf"
+# ⚠️ quantize.exe をプロジェクトルートまたはパスの通った場所にあると仮定
+QUANTIZE_TOOL = "llama-b7247-bin-win-cuda-12.4-x64/llama-quantize.exe"
+
+
+def run_quantization():
+ if not os.path.exists(QUANTIZE_TOOL):
+ print(f"Error: 量子化ツール '{QUANTIZE_TOOL}' が見つかりません。")
+ print("llama.cpp リポジトリから一度だけビルドして取得してください。")
+ return
+
+ if not os.path.exists(INPUT_GGUF):
+ print(
+ f"Error: 入力ファイル '{INPUT_GGUF}' が見つかりません。F16変換を先に実行してください。"
+ )
+ return
+
+ print(f"\n⚛️ GGUF (F16) を Q4_K_M に量子化中...")
+
+ try:
+ subprocess.run(
+ [
+ QUANTIZE_TOOL,
+ INPUT_GGUF,
+ OUTPUT_GGUF,
+ "q4_k_m", # 推奨される量子化手法
+ ],
+ check=True,
+ )
+ print(f"✅ 量子化成功: {OUTPUT_GGUF}")
+
+ except subprocess.CalledProcessError as e:
+ print(f"❌ 量子化失敗: {e}")
+
+
+if __name__ == "__main__":
+ # 最初に convert_merge.py を実行し、F16 GGUF を作成してからこれを実行
+ run_quantization()
diff --git a/reports/diff.typ b/reports/diff.typ
@@ -0,0 +1,153 @@
+#set text(lang: "ja", font: "Noto Sans CJK JP")
+#set par(leading: 1.5em)
+#set heading(numbering: "1.")
+#show heading: set block(below: 1em)
+#set math.equation(numbering: "(1)")
+
+#show figure.where(
+ kind: table
+): set figure.caption(position: top)
+
+#import "@preview/muchpdf:0.1.0": muchpdf
+
+#show regex("[\p{scx:Han}\p{scx:Hira}\p{scx:Kana}]"): set text(font: "Noto Sans CJK JP")
+
+#muchpdf(read("./titlepage.pdf", encoding: none),width: 20cm)
+
+#counter(page).update(0)
+#set page(numbering: "- 1 -")
+
+#let phisics_experiment_table(header, cells) = {
+ table(
+ columns: header.len(),
+ table.hline(),
+ table.header(..header.flatten()),
+ table.hline(),
+ ..cells,
+ table.hline(),
+ )
+}
+
+= 実験目的
+分光計により,波長の分かっている単色光を用いて回折格子の定数(1cm当たりのミゾの本数)を決定すること。
+
+= 実験原理
+回折格子に特定の周波数の光を当てると、特定の方向にのみ光が強く出る。
+その原理は、以下である。
+格子定数nの回折格子があるとする。この回折格子に対して垂直に入射する波長$lambda$の平行光線を入射する。この平行光線が入射方向に対して$phi$だけずれたとすると、平行に出射する光線との経路差は$1/n sin(phi)$となる。したがって、
+$ 1/n sin(phi) = m lambda (m in NN) $
+を満たす$phi$の方向の光の強度が最大になることがわかる。
+これを用いて、回折格子に特定の周波数の光を当て、強く光が出る方向を測定することで、その回折格子の格子定数を求めることができる。
+
+= 実験方法
+実験装置:分光計・ガラス製回折格子・光源(ナトリウムランプ)
+
+この実験は以下の手順に従って、暗室で行った。
+分光計の副尺の読み取りは二箇所の値を読み取り、平均化した値を取った。
+
+1. 望遠鏡の調整
+分光計についている望遠鏡を外し、遠くのものを見て、焦点を合わせた。
+2. 分光計の調整
+望遠鏡の視軸を分光計の回転軸に垂直にし、かつ回折格子の表面を望遠鏡の視線に垂直にした。
+また、コリメーターから出る光を平行にし、その視軸を望遠鏡の視軸と並行にした。
+3. 光源の設置
+スリットの望遠鏡と反対側に光源としてナトリウムランプを置き、ナトリウムランプの電源スイッチを入れると黄色い光が発せられることを確認した。
+また、望遠鏡とコリメーターを同一光軸上に置き、スリットの像が明るくなるように光源の位置を微調整した。
+4. スリットの調整
+望遠鏡を見ながらスリット幅をなるべく細くした。
+5. 回折格子の設置
+コリメーターからの光が回折格子の表面に垂直に入射するように、回折格子を分光計に設置した。
+回折格子の透過光の中心に望遠鏡Tの十字線を合わせて、その読み取り盤の値を読み取り、0次線の角度とした。
+6. n次線の探索
+望遠鏡を上から見て反時計方向(または時計方向)に回転しながら、スリットの像を探した。
+はじめに見つけたスリットの像は-1次(または+1次)の回折戦で形成された像とし、この回折像の中央に4と同様に十字線の中央を合わせ、その時の角度を読み取った。
+さらに同じ方向に回転させて次の回折像を見つけ、同様な測定を-5次(+5次)まで行った。
+
+= 結果
+=== 測定値
+分光計によって得た、光の像の強まる角度を以下にまとめた。
+#figure(
+ caption: [光の強まる角度],
+ kind: table,
+ phisics_experiment_table(
+ ([項目],[5次],[4次],[3次],[2次],[1次],[0次],[-1次],[-2次],[-3次],[-4次],[-5次],),
+ csv("./v.csv").flatten(),
+ )
+)
+=== 測定値の解析
+また、$theta$から$phi$を求めたものを以下にまとめた。
+#figure(
+ caption: [$theta$による$phi$の値],
+ kind: table,
+ phisics_experiment_table(
+ ([],[1次],[2次],[3次],[4次],[5次]),
+ csv("phi.csv").flatten(),
+ )
+)
+次に得られた$phi$の値を元に、それぞれの次数でのnの最確値を求める。
+次数mにおけるnの最確値の式は原理より以下であることが分かる。
+$ n = sin(phi) / (m lambda) $
+ここで、ナトリウムランプから発せられる光の波長を教科書[1]より$5.893 times 10^(-5)$とすると、
+$ n = (sin (phi) / m times 5.893) times 10^5 (本)$と分かる。これらを1~5次までに適応すると、
+#let phis = ("1":"1011.1","2":"999.8","3":"1001.7","4":"998.8","5":"995.1")
+#for (m,o) in phis [
+$ n_(#m) = (sin(phi) / (m times 5.893)) times 10^5= #o (本) $
+]
+
+となる。この結果をまとめると、
+#figure(
+ caption: [次数による$theta$の値],
+ kind: table,
+ phisics_experiment_table(
+ ([次数],[1次],[2次],[3次],[4次],[5次]),
+ ([n (本)],[1011.1],[999.8],[1001.7],[998.8],[995.1]),
+ )
+)
+=== 誤差論
+次にnの偶然誤差について考える。
+nの偶然誤差である$d^2$平均($d := n - $average$(n)$)は、以下の表によって求まる。
+#figure(
+ caption: [nの偶然誤差],
+ kind: table,
+ phisics_experiment_table(
+ ([次数],[1],[2],[3],[4],[5],[平均]),
+ csv("./n-d.csv").flatten(),
+ )
+)
+次にそれぞれの次数における、測定値の誤差によるnへの影響を考える。
+$ phi = (V_1 + (V')_1)/2 - (V_2 + (V')_2)/2 $
+これを式(2)に代入すると、
+$ n = (sin((V_1 + (V'_1))/2 - (V_2 + (V'_2))/2)/(m lambda)) $
+これについて1~5次まで誤差の計算を行う。
+なお、分光計の機械的誤差は0.5分なので角度に直すと$1/120$°となる。
+1次について
+$ delta_n_1 = sqrt(((diff n)/(diff V_1))^2 delta^2_(V_1) + ((diff n)/(diff V'_1))^2 delta^2_(V'_1) + ((diff n)/(diff V_2))^2 delta^2_(V_2) + ((diff n)/(diff V'_2))^2 delta^2_(V'_2)) $
+ルート内の各項は同様の値を持つので、以下は第一項を4倍した値として扱う。
+$ delta_n_1 = sqrt(4 times ((diff n)/(diff V_1))^2 delta^2_(V_1)) $
+$phi_1$を一次における$phi$の最確値とすろと、
+$ delta_n_1 = sqrt(4 times (1/(2 m lambda) cos(phi))^2 delta^2_(V_1)) = sqrt((1/(m times 5.893) times 10^5 times cos(phi) )^2 (1/120)^2) $
+$ = sin(phi_1) / (m times 5.893 times 120) times 10^5 = 141.115... [本] $
+#let deltas = ("2":"70.212","3":"46.3919","4":"34.359","5":"27.039")
+#for (m,delta) in deltas [
+同様にして#m 次は
+$ delta_n_#m = sin(phi_#m) / (#m times 5.893 times 120) times 10^5 = #delta... (本) $
+]
+
+= 考察
+実験より、$n = 1.00 times 10^4 plus.minus 2.8 times 10 [本]$という結果を得た。
+この相対誤差は、$(2.8 times 10)/(1.00 times 10^4) = 2.8%$であった。これにより、ある程度の精度をもって測定することができた。
+また、この誤差の範囲内に、用いた格子の値である$n=1000$は収まっている。
+次に、それぞれの次数でのnの機械的誤差と相対誤差は以下の表のようになっている。
+#figure(
+ caption: [次数によるnの機械的誤差],
+ kind: table,
+ phisics_experiment_table(
+ ([次数],[1],[2],[3],[4],[5]),
+ csv("./diffn.csv").flatten(),
+ )
+)
+この表から次数が上がるとnの誤差が小さくなっていることがわかる。これはnの式にある次数であるmが分母にあるためであると考えられる。
+また、いずれの結果もnの真値である$n=1000$が誤差の範囲内に含まれていることがここからも確認できる。
+
+= 参考文献
+[1] 吉田卯三郎 他著 (三省堂) P.176
diff --git a/reports/feedback_diff.txt b/reports/feedback_diff.txt
@@ -0,0 +1,15 @@
+気圧は0.1の位まで
+原理不足
+図がなくて他人が再現できるか?
+具体的にどうやってピント(焦点)を合わせた?
+コリメーターのピント調整は?
+表の説明文は「表◯に~~を示す」などのように,表の番号も
+波長の単位がない
+表3のタイトル
+表4の単位
+表4は合計も
+5つのnの偶然誤差は?
+最確値±誤差 の表記がない
+偶然誤差の計算方法
+最確値±誤差それぞれにべき乗をつけない,()でくくる
+この考察から,nの測定精度がどうなるか?どういった次数で測定すべきか?
diff --git a/reports/feedback_imp.txt b/reports/feedback_imp.txt
@@ -0,0 +1,7 @@
+記号の後の単位には [ ] を
+回路図記号,~ は記号の下
+実際はオフセット電流はどの程度だったからどうしたのか?
+解析用の欄を示したことも書け
+残差ではあるが,式を書いた方が良い
+最小二乗法の計算式と計算過程を
+数字の後の単位には [ ] は不...
diff --git a/reports/feedback_new.txt b/reports/feedback_new.txt
@@ -0,0 +1,11 @@
+ファイル名
+実験場所
+原理の図がなくて理解が難しい
+どうやってピントを合わせた?
+方法は過去形
+取り付けネジは図の中のどれ?
+途中で反転させないように,具体的にどうやった?
+n=1で,mを1,5,9とした理由が読んでいてわからない
+表2にEを使った書き方がしてあってわかりづらい
+誤差の式と計算過程
+図2はmが大きいとRが大きくなるような図に見える
diff --git a/reports/imp.typ b/reports/imp.typ
@@ -0,0 +1,178 @@
+#set text(lang: "ja", font: "Noto Sans CJK JP", size: 10.5pt)
+#set par(leading: 1.5em)
+#set heading(numbering: "1.")
+#show heading: set block(below: 1em)
+#set math.equation(numbering: "(1)")
+
+#show figure.where(
+ kind: table
+): set figure.caption(position: top)
+
+#import "@preview/muchpdf:0.1.0": muchpdf
+
+#show regex("[\p{scx:Han}\p{scx:Hira}\p{scx:Kana}]"): set text(font: "Noto Sans CJK JP")
+
+#muchpdf(read("./titlepage.pdf", encoding: none),width: 20cm)
+
+#counter(page).update(0)
+#set page(numbering: "- 1 -")
+
+#let phisics_experiment_table(header, cells) = {
+ table(
+ columns: header.len(),
+ table.hline(),
+ table.header(..header.flatten()),
+ table.hline(),
+ ..cells,
+ table.hline(),
+ )
+}
+
+= 実験目的
+直流抵抗と自己インダクタンスとを直列に接続した回路であるインピーダンスダイアグラムを作り,遅れの角および自己インダクタンスを算出すること.
+
+= 実験原理
+直流抵抗(抵抗値$R$Ω)と自己インダクタンス($H$L)を直列に接続したインピーダンスダイアグラムがあるとする.これに電圧$V$Vの直流電流を流したとき,流れる定常電流を$i$Aとするとオームの法則により抵抗値のRが次式より求まる.
+$ R = V/i $
+またこれに周波数$nu$Hzの交流電流($V=V_0 sin(2 pi nu t)$流すと,一般化されたオームの法則から$V - L (d i)/(d t) = R i$(ここで$i$は流れている電流)であるので次式が成り立つ.
+$ L (d i)/(d t) + R i = V_0 sin(2 pi nu t) $
+この式の解を最大電流$i_0$と遅れの角$phi$を使って$i = i_0 sin(2 pi nu t - phi)$と書けると仮定すると,これを上式に代入して,最大電流$i_0$と遅れの角$phi$は以下のように決定される.
+$ cases(
+ i_0 = V_0/sqrt(R^2+4 pi^2 nu^2 L^2),
+ phi = tan^(-1)((2 pi nu L)/R)
+) $
+ここで,$V_e, i_e$をそれぞれ有効電圧,実行電圧とすると,
+$ sqrt(R^2 + 4 pi^2 nu^2 L^2) = V_0/i_0 = V_e/i_e $
+が成り立つ.上記から交流電圧計と交流電流計を用いてインピーダンス($sqrt(R^2 + 4 + pi^2 nu^2 L^2)$)を求めることができる.
+直流電圧流したときの結果より直流抵抗の抵抗値$R$,交流電圧を流したときの結果よりインピーダンス$sqrt(R^2 + 4 + pi^2 nu^2 L^2)$を求められれば,$2 pi nu L$の値が求められる.
+従って遅れの角$phi$を算出することができ,周波数計により交流周波数を測定すると自己インダクタンス$L$を求めることができる.
+
+= 実験方法
+実験装置:直流電源・スライダック・鉄心入りコイル・直流電流計・直流電圧計・交流電流計・交流電圧計・可変抵抗
+
+まず実験装置を用いて回路を作った.
+直流の回路は図1,交流の回路図2に示すような回路にした.
+#figure(
+ kind: image,
+ caption: [直流回路],
+ image("./dccircit.png"),
+)
+#figure(
+ kind: image,
+ caption: [交流回路],
+ image("./accircit.png"),
+)
+
+== 直流回路の測定
+1. 可変抵抗の値をできるだけ小さくした.
+2. 直流電源のツマミを0にして,プラグを接続して電源を入れた.
+3. 電流値が0.1Aになるように,VOLTAGEのつまみをまわし,次にCURRENTのつまみを回して定電流を流した.
+4. 電流計・電圧計の数値が安定しないときは,可変抵抗の値を少しだけ大きくし,再度電流が0.1Aになるように定電流を流した.
+5. 値が安定したら,そのときの電流計と電圧計の値を測定した.
+6. 4から5の操作を電流が0.1Aから1.0Aまで0.1Aづつ増加させて計測した.
+
+== 交流回路の測定
+1. 直流回路から電源・電流計・電圧計だけを変更し,その他は動かさないように回路を組み替えた.
+2. スライダックのつまみを0にして,プラグを接続した.
+ここで,交流電源にはコンセントから給電したスライダックを用いたそのため,周波数は西日本のコンセントの周波数である60Hzになった.
+3. スライダックのつまみを回し,電流計の値が0.1Aになるように電流を流した.
+スライダックはつまみを0にしていてもオフセット電流が流れる.オフセット電流が0.1Aよりも大きい場合はそれを1つ目の測定値とした.
+4. 値が安定したら,その時の電流計と電圧計の値を測定した.
+5. 3から4の操作を電流が0.1Aから1.0Aまで0.1Aづつ増加させて測定した.
+
+= 結果
+直流回路により,得られた値を表1に示す.
+#figure(
+ kind: table,
+ caption: [直流回路のI-V特性],
+ phisics_experiment_table(
+ ("測定番号","1","2","3","4","5","6","7","8","9","10","合計"),
+ csv("current.csv").flatten(),
+ )
+)
+
+交流回路により,得られた値を表2に示す.
+#figure(
+ kind: table,
+ caption: [交流回路のI-V特性],
+ phisics_experiment_table(
+ ("測定番号","1","2","3","4","5","6","7","8","9","10","合計"),
+ csv("voltage.csv").flatten(),
+ )
+)
+以上の結果より,最小二乗法を用いて,それぞれの回路のI-V特性を求めた.
+直流回路について
+$ V = R I + V_0_r $とすると
+$ V = 7.777576 I + 0.177333 $
+なので,
+$ R = (777 plus.minus 6) times 10^(-2) ["Ω"] $
+$ V_0_r = (17 plus.minus 4) times 10^(-2) ["Ω"] $
+また,交流回路について
+$ V = Z I + V_0_z $
+$ V = 14.5697 I - 0.07333 $
+したがって,
+$ Z = (145 plus.minus 3) times 10^(-1) ["Ω"] $
+$ V_0_z = (0 plus.minus 2) times 10^(-1) ["Ω"] $
+
+これにより,自己インダクタンス$L$とその誤差$sigma_L$は,
+$ Z^2 = R^2 + 2 pi^2 nu^2 L^2 $
+より
+$ L = sqrt(Z^2 - R^2)/(2 pi nu) = 3.2680 times 10^(-2) ["Ω"] $
+$ sigma_L = 1/(2 pi nu sqrt(Z^2-R^2)) sqrt(Z^2 (sigma_Z)^2 - R^2 (sigma_R)^2) = 8.5 times 10^(-4) ["Ω"] $
+$ L = (327 plus.minus 9) times 10^(-4) ["Ω"] $
+それにより,遅れの角$phi$とその誤差$sigma_phi$は,
+$ phi = tan^(-1)((2 pi nu L)/R ) = 1.007686... ["rad"] $
+$ sigma_phi = (2 pi nu)/(4 pi^2 nu^2 L^2 + R^2) sqrt(R^2 (sigma_R)^2 + L^2 (sigma_L)^2) ["rad"] $
+$ phi = (57 plus.minus 5 ) times 10 [°] $
+
+= 考察
+実験より,回路に用いた鉄心入りコイルのリアクタンス$L$は,
+$ L = (327 plus.minus 9) times 10^(-4) ["Ω"] $
+また,遅れの角$phi$は,
+$ phi = (57 plus.minus 5 ) times 10 [°] $
+であると求まった.
+リアクタンスの相対誤差は,$9/327 = 0.027522... tilde.eq.rev 3%$
+遅れの角の相対誤差は$5/57 = 0.087719... tilde.eq.rev 9%$
+である.この値より,十分な精度は出ていないといえる.
+特に交流の0.1Aに関しては,以下の追加課題で示すグラフを見ると,他の測定点に対して一直線上から離れた点を示している.この点を除いて計算をし直すと,
+$ L' = (316 plus.minus 6) times 10^(-4) ["Ω"] $
+$ phi' = (56 plus.minus 5 ) times 10 [°] $
+となり,Lの相対誤差は$6/316 = 0.0189... tilde.eq.rev 2%$
+phiの相対誤差は$5/56 = 0.0847400... tilde.eq.rev 8%$
+であり,数値が少し改善した.
+この測定の誤差が大きくなった原因として,測定をするときに電流と電圧がなかなか安定しておらず,不安定なまま測定を行ってしまい,測定の精度が低下したことが考えられる.
+
+== 追加課題について
+=== 設問1
+以下の図3に作成したインピーダンスダイヤグラムを示す.
+#figure(
+ kind: image,
+ caption: [作成したインピーダンスダイヤグラム],
+ image("2025111901.jpg"),
+)
+
+=== 設問2
+三角形ABCは円に内接しており,ACはその円の中心を通っている.これとタレスの定理より,この三角形ABCは角Bが直角であることが分かる.
+ピタゴラスの定理より,
+$ R^2 = "AB"^2 + Z^2 $
+$ R^2 = "AB"^2 + R^2 + 4 pi^2 nu^2 L^2$
+$ "AB"^2 = 4 pi^2 nu^2 L^2 $
+$ "AB" = 2 pi nu L $
+よって$"AB" = 2 pi nu L$が示された.
+
+=== 設問3
+以下に測定値とその誤差を示す.
+ただし,器械的誤差は最小メモリ0.01cmなので,0.005cmとすべきだが,有効数字が足りないので,0.01cmとしている.
+$ "AC(Z)" = 14.50 plus.minus 0.01 ["cm"] $
+$ "CD(R)" = 7.95 plus.minus 0.01 ["cm"] $
+$ "AB" = 12.16 plus.minus 0.01 ["cm"] $
+$"AB" = 2 pi nu L$より$L = "AB" / (2 pi nu)$より,
+$ L = 0.03225 plus.minus 0.00001 ["Ω"] $
+
+=== 設問4
+今回の実験で可変抵抗をできるだけ小さくした理由は,もし可変抵抗を大きくすると,
+$ Z = sqrt(R^2 + (4 pi^2 nu^2 L^2)) $
+の$R^2$の項が大きくなるので,リアクタンスの含まれる項の影響が相対的に小さくなってしまい,誤差が大きく出てしまうから.
+
+= 参考文献
+[1] 吉田卯三郎 他著 (三省堂) P.257
diff --git a/reports/new.typ b/reports/new.typ
@@ -0,0 +1,140 @@
+#set text(lang: "ja", font: "Noto Sans CJK JP")
+#set par(leading: 1.5em)
+#set heading(numbering: "1.")
+#show heading: set block(below: 1em)
+#set math.equation(numbering: "(1)")
+
+#show figure.where(
+ kind: table
+): set figure.caption(position: top)
+
+#import "@preview/muchpdf:0.1.0": muchpdf
+
+#show regex("[\p{scx:Han}\p{scx:Hira}\p{scx:Kana}]"): set text(font: "Noto Sans CJK JP")
+
+#muchpdf(read("./titlepage.pdf", encoding: none),width: 20cm)
+
+#counter(page).update(0)
+#set page(numbering: "- 1 -")
+
+#let phisics_experiment_table(header, cells) = {
+ table(
+ columns: header.len(),
+ table.hline(),
+ table.header(..header.flatten()),
+ table.hline(),
+ ..cells,
+ table.hline(),
+ )
+}
+
+= 実験目的
+ナトリウムランプから発せられる単色光によるニュートンリングを作るレンズの曲率半径を測定すること。
+
+= 実験原理
+平行ガラス板BB′上に曲率半径Rの非常に大きな平凸レンズAA′を置いたとし、波長λの単色光をこれに垂直に入射させる。この場合、空気層ABまたはA′B′は、きわめて薄いと考えられるので、入射光も反射光もほぼ平行とみなすことができる。
+したがって、空気層の上面AA′からの反射光と、下面BB′からの反射光との光路差を求めるには、
+$ A B = A'B' = O D = z, A D = A'D' = r, E D = 2R-z $
+とすると、
+$ r^2 = (2R-z)z = 2R z - z^2 tilde.equiv 2R z $
+これに加えて、AA'からの反射光は密から疎な媒質への境の反射であり、BB'からの反射光は疎から密への境の反射であるので、経路差とすべきのは上式から導かれる光路差に半波長を足したものであると考えられる。
+これらを踏まえて全光路差は$2z+ lambda/2$であることが分かる。
+したがって、m番目のr、$r_m$に成り立つ関係式は
+$ r^2_m = m lambda R ( m in NN ) $
+だと分かる。この式から次を考えると、
+$ r^2_m - r^2_(m + n) = n lambda R (m,n in NN) $
+故に
+$ R = (r^2_m - r^2(m+n))/(n lambda) $
+が求まる。
+以上より、m本目とm+n本目のニュートンリングの直径を測定することで、Rを間接的に測定することができる。
+
+= 実験方法
+実験器具:ニュートンリング測定装置、ナトリウムランプ、集光レンズ
+
+この実験は以下の手順に従って、暗室で行った。
+数値の測定はマイクロメーターによって行った。
+また、実験器具の配置と光の経路を図1に示した。
+#figure(
+ caption: [実験器具の配置と光の経路],
+ kind: image,
+ image("fig1.jpg"),
+)
+
+1. 実験器具の配置
+ニュートンリング測定装置を設置する。その正面にナトリウムランプを設置する。ニュートンリング測定装置とナトリウムランプの間に集光レンズを設置し、ニュートンリング測定装置へ入射する光が平行な光になるようにする。
+
+2. 器具の調整
+ナトリウムランプの電源をつけ、ニュートンリング測定装置についている遊動顕微鏡を覗く。
+ニュートンリングが見えたらばピント合わせ、半透明反射鏡を傾けて、ニュートンリングが明るく見えるように調節する。
+
+3. 最初の位置合わせ
+ニュートンリングの中心を遊動顕微鏡の十字線の軌跡が通過するようにリングの取り付けネジを調整しリングの中心を移動させる。この場合にニュートンリングが真円からずれないように注意をする。
+
+4. 測定
+m番目の暗輪(または明輪)に遊動顕微鏡の十字線を合わせて、マイクロメーターでその時の値を読み取る。
+次に、m-1番目の暗輪(または明輪)に遊動顕微鏡の十字線を合わせてそのときの値を読み取る。
+同様な測定を-m番目まで行う。ここでmの値は10以上とし、0番目のリングの測定も忘れないように行う。
+ここで移動機構の遊びを避けるため、移動方向を途中で反転させないように気をつける。
+
+
+= 結果
+=== 測定値
+測定で得た、m番目のニュートンリングの値を表1にまとめた。
+なお、$m$が負のものは$(a_m)'$として表にまとめている。
+#figure(
+ caption: [ニュートンリングの位置],
+ kind: table,
+ phisics_experiment_table(
+ ("m","1","2","3","4","5","6","7","8","9","10"),
+ csv("a_m.csv").flatten(),
+ ),
+)
+=== 測定値の解析
+また、上記の値から$R$の値を求めた。
+mとnの値は次のように選んだ。
+nが大きいとき、小さいサイズのリングから大きいサイズのリングまでを取ることができ、レンズに歪みがあった場合に平均的な曲率半径を取ることができると考えた。
+逆に、$n=1$と極端に小さくしたときは局所的な曲率半径を求めることができるので、$m=1,m=5,m=9$のときについてそれぞれ曲率半径Rを求めた。
+ただし、ナトリウムランプから発せられる単色光の波長は参考文献[1]より、$5.893 times 10^(-7)$の値を用いた。
+==== Case: m=1 n=9
+$ R = ((a_10 - a's_10)^2 - (a_1 - a'_1)^2)/(4 times 9 times lambda) = ((7.224 times 10^(-3))^2 times (5.55 times 10^(-3))^2)/(4 times 9 times lambda) $
+$ = ((52.19-6.503)times 10^(-6))/(4 times 9 times lambda) = (4.56837 times 10^(-6))/(4 times 9 times 5893 times 10^(-10)) = 2.1534 (m) $
+
+==== Case: m=1 n=1
+$ R = ((a_2 - a's_2)^2 - (a_1 - a'_1)^2)/(4 times 1 times lambda) = ((3.417 times 10^(-3))^2 times (2.55 times 10^(-3))^2)/(4 times 1 times lambda) $
+$ = ((1.168-0.065025)times 10^(-6))/(4 times 1 times lambda) = (5.17339 times 10^(-6))/(4 times 1 times 5893 times 10^(-10)) = 2.1947 (m) $
+
+==== Case: m=5 n=1
+$ R = ((a_6 - a's_6)^2 - (a_5 - a'_5)^2)/(4 times 1 times lambda) = ((5.613 times 10^(-3))^2 times (5.144 times 10^(-3))^2)/(4 times 1 times lambda) $
+$ = ((3.151-2.646)times 10^(-6))/(4 times 1 times lambda) = (5.045 times 10^(-6))/(4 times 1 times 5893 times 10^(-10)) = 2.1403 (m) $
+
+==== Case: m=9 n=1
+$ R = ((a_10 - a's_10)^2 - (a_9 - a'_9)^2)/(4 times 1 times lambda) = ((7.24 times 10^(-3))^2 times (6.869 times 10^(-3))^2)/(4 times 1 times lambda) $
+$ = ((5.129-4.718)times 10^(-6))/(4 times 1 times lambda) = (5.003 times 10^(-6))/(4 times 1 times 5893 times 10^(-10)) = 2.1224 (m) $
+
+==== Rの偶然誤差
+上記で求めた曲率半径の偶然誤差を計算した表を以下に示す。
+#figure(
+ caption: [求めたRの偶然誤差],
+ kind: table,
+ phisics_experiment_table(
+ ("n,m","m=1,n=9","m=1,n=1","m=5,n=1","m=9,n=1","平均値"),
+ csv("r.csv").flatten(),
+ ),
+)
+以上から、誤差は$7.1 times 10^(-4)$と求まった。
+
+= 考察
+実験から、曲率半径Rは$R = 2.1527 plus.minus 7 times 10^(-4)$と求まった。また、Rの相対誤差は3%と求まった。
+また、$n=1$のときのmと曲率半径Rの関係としては、mが大きくなるほどRが小さな値になる傾向が見られた。
+この原因として考えられるのは、レンズの固定のためにレンズの縁をネジで押し付けて固定しているため、レンズの縁に曲率と逆の向きに圧力がかかっていることが考えられる。
+また、リングの次数が上がるにつれ、縁に近いことやレンズの厚さが増すことで、圧力による曲率の変化が縁に近づくにつれて大きくなっている事が考えられる。
+これを概念的に図示すると以下の図のようになる。
+#figure(
+ caption: [レンズの歪み方の概念図],
+ kind: image,
+ image("fig2.jpg"),
+)
+
+
+= 参考文献
+[1] 吉田卯三郎 他著 (三省堂) P.182
diff --git a/requirements.txt b/requirements.txt
@@ -0,0 +1,18 @@
+google-genai
+torch
+transformers
+peft
+accelerate
+bitsandbytes
+datasets
+scipy
+sentencepiece
+fastapi
+uvicorn
+pydantic
+fastapi
+uvicorn
+pydantic
+numpy
+llama-cpp-python
+requests
diff --git a/review_typst.py b/review_typst.py
@@ -0,0 +1,64 @@
+import os
+
+from llama_cpp import Llama
+
+MODEL_PATH = "./mistral_typst_quantized.gguf"
+FILE_PATH = "tran.typ"
+N_CTX = 8192
+MAX_TOKENS = 8192
+
+if not os.path.exists(MODEL_PATH):
+ print(f"Error: Model file not found at {MODEL_PATH}")
+ exit(1)
+
+if not os.path.exists(FILE_PATH):
+ print(f"Error: Typst file not found at {FILE_PATH}")
+ exit(1)
+
+try:
+ with open(FILE_PATH, "r", encoding="utf-8") as f:
+ typst_content = f.read()
+except Exception as e:
+ print(f"Error reading file: {e}")
+ exit(1)
+
+llm = Llama(
+ model_path=MODEL_PATH,
+ n_gpu_layers=0,
+ n_ctx=N_CTX,
+ verbose=True,
+)
+
+SYSTEM_PROMPT = (
+ "あなたはTypstコードのレビュー専門家です。提供されたコードを分析し、"
+ "問題点、警告、改善点を日本語でリストアップしてください。"
+ "技術的なエラーだけでなく、Typstの慣習やベストプラクティスに従っていない点も指摘します。"
+ "出力は、Markdownの箇条書き形式(- [種別] メッセージ)で簡潔に記述してください。"
+ "余計な前置きや結論の文章は一切不要です。"
+)
+
+USER_PROMPT = (
+ f"以下のTypstコードをレビューしてください。\n\n```typst\n{typst_content}\n```"
+)
+
+prompt = f"### System:\n{SYSTEM_PROMPT}\n\n### User:\n{USER_PROMPT}\n\n### Assistant:"
+
+print("--- Llama モデルの初期化完了 (CPU Mode) ---")
+print(f"レビュー対象ファイル: {FILE_PATH} ({len(typst_content)} chars)")
+print("--- 推論開始 (時間がかかる可能性があります) ---")
+
+try:
+ completion = llm.create_completion(
+ prompt=prompt,
+ max_tokens=MAX_TOKENS,
+ temperature=0.1,
+ stop=["### User:", "### System:"],
+ )
+
+ print("\n\n--- レビュー結果 ---")
+ print(completion["choices"][0]["text"].strip())
+ print("--------------------")
+
+except Exception as e:
+ print(f"\n\n--- 推論中にエラーが発生しました ---")
+ print(f"エラー: {e}")
diff --git a/structured-feedback/structured_data_001.json b/structured-feedback/structured_data_001.json
@@ -0,0 +1,32 @@
+[
+ {
+ "type": "format",
+ "location": "全体",
+ "text": "数字の後の単位には [ ] を使用しないでください。記号の後の単位の表記についても確認してください。"
+ },
+ {
+ "type": "format",
+ "location": "図1, 図2",
+ "text": "回路図記号のチルダ(~)は記号の下に配置してください。"
+ },
+ {
+ "type": "detail",
+ "location": "交流回路の測定, 3.",
+ "text": "交流回路の測定において、オフセット電流が実際にどの程度だったのか、そしてそれに対してどのような対応を取ったのかを具体的に記述してください。"
+ },
+ {
+ "type": "methodology",
+ "location": "結果",
+ "text": "最小二乗法などの解析に用いたデータやグラフの「解析用の欄」(例:軸の範囲、データ点など)を示したことについても記述してください。"
+ },
+ {
+ "type": "logic",
+ "location": "結果, 最小二乗法の結果の式",
+ "text": "最小二乗法によるフィッティング結果の残差について言及するならば、その式も記述した方が良いでしょう。または、$V_0_r$や$V_0_z$のような切片項の意味を明確にしてください。"
+ },
+ {
+ "type": "methodology",
+ "location": "結果",
+ "text": "最小二乗法の計算式と計算過程を詳細に記述してください。"
+ }
+]+
\ No newline at end of file
diff --git a/structured-feedback/structured_data_002.json b/structured-feedback/structured_data_002.json
@@ -0,0 +1,77 @@
+[
+ {
+ "type": "detail",
+ "location": "全体",
+ "text": "気圧は0.1の位まで記載してください。"
+ },
+ {
+ "type": "logic",
+ "location": "実験原理",
+ "text": "実験原理の説明が不足しています。より詳細な説明が必要です。"
+ },
+ {
+ "type": "clarity",
+ "location": "実験方法",
+ "text": "実験装置の図がないため、他人が実験を再現できるか不明です。図の追加を検討してください。"
+ },
+ {
+ "type": "clarity",
+ "location": "実験方法, 1. 望遠鏡の調整",
+ "text": "望遠鏡のピント(焦点)を具体的にどのように合わせたのか説明が必要です。"
+ },
+ {
+ "type": "clarity",
+ "location": "実験方法, 2. 分光計の調整",
+ "text": "コリメーターのピント調整について説明がありません。詳細を追加してください。"
+ },
+ {
+ "type": "format",
+ "location": "全体",
+ "text": "表の説明文は「表◯に~~を示す」のように、表の番号を含めて記述してください。"
+ },
+ {
+ "type": "format",
+ "location": "結果, nの最確値の式",
+ "text": "ナトリウムランプから発せられる光の波長の値に単位がありません。単位を追記してください。"
+ },
+ {
+ "type": "format",
+ "location": "結果, 3つ目の表 (caption: [次数による$theta$の値])",
+ "text": "表3のタイトルが内容と一致していません。現在のタイトルは「次数による$theta$の値」ですが、内容はnの値です。修正してください。"
+ },
+ {
+ "type": "format",
+ "location": "結果, 4つ目の表 (caption: [nの偶然誤差])",
+ "text": "表4の単位が不足しています。適切な単位を追記してください。"
+ },
+ {
+ "type": "content",
+ "location": "結果, 4つ目の表 (caption: [nの偶然誤差])",
+ "text": "表4に合計値も記載してください。"
+ },
+ {
+ "type": "analysis",
+ "location": "結果, 誤差論",
+ "text": "5つのnの偶然誤差について、具体的な計算や考察が不足しています。詳細を追加してください。"
+ },
+ {
+ "type": "format",
+ "location": "考察",
+ "text": "最終的な結果(nの値)を「最確値±誤差」の形式で表記してください。"
+ },
+ {
+ "type": "clarity",
+ "location": "結果, 誤差論",
+ "text": "偶然誤差の計算方法について、より詳細な説明が必要です。"
+ },
+ {
+ "type": "format",
+ "location": "考察, n = 1.00 times 10^4 plus.minus 2.8 times 10 [本]",
+ "text": "「最確値±誤差」の表記において、べき乗は全体にかかるように括弧でくくり、それぞれにべき乗をつけないでください(例:$(1.00 \times 10^4 \times \text{本}) \times (1 \times 10^4 \times \text{本})$)。"
+ },
+ {
+ "type": "analysis",
+ "location": "考察",
+ "text": "考察において、nの測定精度がどうなるか、またどのような次数で測定すべきかについて、より深い分析と結論を述べてください。"
+ }
+]+
\ No newline at end of file
diff --git a/structured-feedback/structured_data_003.json b/structured-feedback/structured_data_003.json
@@ -0,0 +1,57 @@
+[
+ {
+ "type": "metadata",
+ "location": "全体",
+ "text": "レポートのファイル名に関する情報が不足しています。"
+ },
+ {
+ "type": "metadata",
+ "location": "実験方法",
+ "text": "実験場所(例:研究室名、部屋番号)が記載されていません。"
+ },
+ {
+ "type": "clarity",
+ "location": "実験原理",
+ "text": "実験原理の説明に図がないため、ニュートンリングの形成メカニズムや光路差の導出が視覚的に理解しにくいです。"
+ },
+ {
+ "type": "method",
+ "location": "実験方法 2. 器具の調整",
+ "text": "ニュートンリングのピント合わせについて、具体的な調整方法(例:どのネジをどのように動かしたか)が不明です。"
+ },
+ {
+ "type": "grammar",
+ "location": "実験方法",
+ "text": "実験方法の記述が「行った」「した」などの過去形になっています。一般的に、実験レポートの方法は現在形または未来形(~する)で記述します。"
+ },
+ {
+ "type": "clarity",
+ "location": "実験方法 3. 最初の位置合わせ",
+ "text": "「リングの取り付けネジ」が図1のどの部分を指すのか、図中に明記されていないため分かりにくいです。"
+ },
+ {
+ "type": "method",
+ "location": "実験方法 4. 測定",
+ "text": "移動機構の遊びを避けるため「移動方向を途中で反転させないように気をつける」とありますが、具体的にどのような手順で測定を行ったのか(例:一方向にのみ移動させた、測定順序など)が不明です。"
+ },
+ {
+ "type": "logic",
+ "location": "測定値の解析",
+ "text": "n=1のケースでmを1, 5, 9と選んだ理由について、説明が不足しており、読者が意図を理解しにくいです。"
+ },
+ {
+ "type": "format",
+ "location": "Rの偶然誤差 (表2)",
+ "text": "表2「求めたRの偶然誤差」の数値が指数表記(Eを使った書き方)で記載されており、読みにくいです。一般的な数値表記に修正してください。"
+ },
+ {
+ "type": "calculation",
+ "location": "Rの偶然誤差",
+ "text": "曲率半径Rの偶然誤差を計算したとありますが、その計算式と具体的な計算過程が記載されていません。"
+ },
+ {
+ "type": "clarity",
+ "location": "考察 (図2)",
+ "text": "図2「レンズの歪み方の概念図」が、mが大きくなるほどRが大きくなるように見えます。しかし、考察では「mが大きくなるほどRが小さな値になる傾向が見られた」とあり、図と考察の内容が矛盾しているように見えます。図の表現を修正するか、説明を補足してください。"
+ }
+]+
\ No newline at end of file
diff --git a/structuring-training-data.py b/structuring-training-data.py
@@ -0,0 +1,112 @@
+import glob
+import json
+import os
+
+from google import genai
+from google.genai import types
+
+
+def find_next_sequence_number(base_name: str, file_extension: str) -> int:
+ """既存のファイル名から最大の連番を見つけ、次の連番を返す"""
+ # 例: structured_data_*.json にマッチ
+ search_pattern = f"{base_name}_*{file_extension}"
+ existing_files = glob.glob(search_pattern)
+
+ max_num = 0
+
+ for filename in existing_files:
+ # ファイル名から数字部分を抽出
+ # 例: structured_data_005.json -> '005'
+ try:
+ # base_name_ の直後から .file_extension の直前までの文字列を取得
+ start_index = len(base_name) + 1
+ end_index = filename.rfind(file_extension)
+ if end_index != -1 and end_index > start_index:
+ num_str = filename[start_index:end_index]
+ if num_str.isdigit():
+ max_num = max(max_num, int(num_str))
+ except:
+ continue
+
+ return max_num + 1
+
+
+def generate_structured_json(
+ typst_file_path: str, feedback_file_path: str, base_output_name: str
+):
+ client = genai.Client()
+
+ # 次の連番を取得 (例: 001, 002, ...)
+ next_num = find_next_sequence_number(base_output_name, ".json")
+ output_file_path = f"{base_output_name}_{next_num:03d}.json"
+
+ with open(typst_file_path, "r", encoding="utf-8") as f:
+ typst_content = f.read()
+
+ with open(feedback_file_path, "r", encoding="utf-8") as f:
+ feedback_content = f.read()
+
+ system_instruction = "あなたは、提供されたTypstレポートとそのフィードバックを構造化するための専門家です。入力テキストから、指摘事項を分析し、指定されたJSONスキーマに厳密に従って、指摘事項のリストを生成してください。応答はJSON形式のみとし、Markdownの装飾や説明文は一切含めないでください。"
+
+ json_schema = {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "指摘のカテゴリ(例:format, logic, grammar, citationなど)。",
+ },
+ "location": {
+ "type": "string",
+ "description": "Typstファイル内の指摘箇所(例:line 25-30, 全体)。",
+ },
+ "text": {
+ "type": "string",
+ "description": "フィードバックの具体的な内容。",
+ },
+ },
+ "required": ["type", "location", "text"],
+ },
+ }
+
+ prompt = (
+ f"Typstファイルの内容:\n---\n{typst_content}\n---\n\n"
+ f"対応するフィードバックの生テキスト:\n---\n{feedback_content}\n---"
+ )
+
+ response = client.models.generate_content(
+ model="gemini-2.5-flash",
+ contents=[prompt],
+ config=types.GenerateContentConfig(
+ system_instruction=system_instruction,
+ response_mime_type="application/json",
+ response_schema=json_schema,
+ temperature=0.1,
+ ),
+ )
+
+ structured_json_data = json.loads(response.text)
+
+ with open(output_file_path, "w", encoding="utf-8") as f:
+ json.dump(structured_json_data, f, ensure_ascii=False, indent=2)
+
+ print(f"構造化されたJSONを {output_file_path} に保存しました。")
+
+
+if __name__ == "__main__":
+ # 使用例:ファイル名を適切に置き換えてください
+ TYPST_REPORT = "report_001.typ"
+ FEEDBACK_TEXT = "feedback_001.txt"
+
+ # 出力ファイルのベース名。連番と.jsonが自動で付加されます。
+ OUTPUT_BASE_NAME = "structured_data"
+
+ if not os.getenv("GEMINI_API_KEY"):
+ print("エラー: 環境変数 GEMINI_API_KEY が設定されていません。")
+ else:
+ generate_structured_json(
+ typst_file_path=TYPST_REPORT,
+ feedback_file_path=FEEDBACK_TEXT,
+ base_output_name=OUTPUT_BASE_NAME,
+ )
diff --git a/train.py b/train.py
@@ -0,0 +1,142 @@
+import torch
+from datasets import load_dataset
+from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
+from transformers import (
+ AutoModelForCausalLM,
+ AutoTokenizer,
+ BitsAndBytesConfig,
+ Trainer,
+ TrainingArguments,
+)
+
+# --- 設定 ---
+MODEL_NAME = "mistralai/Mistral-7B-Instruct-v0.2" # 高性能なベースモデル
+DATASET_PATH = "typst_feedback_dataset.jsonl" # 統合した学習データセット
+OUTPUT_DIR = "./mistral_typst_adapter" # 学習結果(LoRAアダプター)の保存先
+LORA_R = 16 # LoRAのランク(精度とメモリのトレードオフ)
+LORA_ALPHA = 32
+LORA_DROPOUT = 0.05
+BATCH_SIZE = 1
+
+# --- 1. データセットの準備 ---
+# JSON Linesファイルをロード
+dataset = load_dataset("json", data_files=DATASET_PATH, split="train")
+
+
+def format_prompt(example):
+ """
+ Typstコードを入力(Instruction)として、JSON出力を期待するプロンプト形式に整形する。
+ MistralのInstructionフォーマット([INST]...[/INST])を使用。
+ """
+
+ # 指示: Typstコードをレビューし、JSON形式で指摘事項を出力せよ
+ prompt = f"""[INST]
+以下のTypstコードのレビューを行い、文書のフォーマット、論理、文法に関するすべての指摘事項を、定義されたJSON形式のリストとして出力してください。
+
+Typstコード:
+---
+{example["instruction"]}
+---
+
+JSON形式の指摘リスト:
+[/INST]"""
+
+ # LLMの学習データは 'Instruction' と 'Output' を結合した形式にする
+ example["text"] = prompt + example["output"]
+ return example
+
+
+# データセットをプロンプト形式に変換
+dataset = dataset.map(format_prompt, remove_columns=["instruction", "output"])
+
+# トークナイザをロード(修正済みセクション)
+tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
+tokenizer.pad_token = tokenizer.eos_token
+
+
+def tokenize_function(examples):
+ tokenized = tokenizer(
+ examples["text"], truncation=True, padding="max_length", max_length=1024
+ )
+ # 【✅ 修正箇所】
+ # input_idsを複製してlabelsとする
+ # Data Collatorがinput_ids(モデル入力)とlabels(教師データ)の両方を見つけられるようにする
+ tokenized["labels"] = tokenized["input_ids"].copy()
+ return tokenized
+
+
+tokenized_dataset = dataset.map(
+ tokenize_function, batched=True, remove_columns=["text"]
+)
+
+# --- 2. 量子化設定とモデルのロード ---
+# QLoRAのための4bit量子化設定
+bnb_config = BitsAndBytesConfig(
+ load_in_4bit=True,
+ bnb_4bit_quant_type="nf4",
+ bnb_4bit_compute_dtype=torch.bfloat16,
+ bnb_4bit_use_double_quant=False,
+)
+
+# モデルとトークナイザをロード
+model = AutoModelForCausalLM.from_pretrained(
+ MODEL_NAME,
+ quantization_config=bnb_config,
+ device_map="auto",
+)
+tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
+tokenizer.pad_token = tokenizer.eos_token # トークナイザ設定
+
+# 4bit学習のためのモデル準備
+model.gradient_checkpointing_enable()
+model = prepare_model_for_kbit_training(model)
+
+
+# --- 3. LoRA設定とモデル適用 ---
+lora_config = LoraConfig(
+ r=LORA_R,
+ lora_alpha=LORA_ALPHA,
+ lora_dropout=LORA_DROPOUT,
+ bias="none",
+ task_type="CAUSAL_LM", # テキスト生成タスク
+ target_modules=[
+ "q_proj",
+ "k_proj",
+ "v_proj",
+ "o_proj",
+ ], # Mistralの主要なAttention層
+)
+
+# PEFTモデルの取得
+model = get_peft_model(model, lora_config)
+model.print_trainable_parameters() # 学習対象のパラメータ数を確認(非常に少ないはず)
+
+
+# --- 4. 学習の実行 ---
+# 【✅ 修正 2: TrainingArgumentsの設定変更】
+training_args = TrainingArguments(
+ output_dir=OUTPUT_DIR,
+ per_device_train_batch_size=BATCH_SIZE,
+ gradient_accumulation_steps=4,
+ warmup_steps=10,
+ max_steps=25,
+ learning_rate=2e-4,
+ fp16=True,
+ logging_steps=5,
+ # 【ここを修正】データセットの列名がTrainerと完全に一致しなくても許容する
+ remove_unused_columns=False,
+)
+
+trainer = Trainer(
+ model=model,
+ # 【修正 3: トークン化後のデータセットを使用】
+ train_dataset=tokenized_dataset,
+ args=training_args,
+ tokenizer=tokenizer,
+)
+
+# 学習開始
+trainer.train()
+
+# 学習済みアダプターの保存
+trainer.model.save_pretrained(OUTPUT_DIR)
diff --git a/tran.typ b/tran.typ
@@ -0,0 +1,11 @@
+
+= 実験目的
+NPN型トランジスタの静特性を測定すること.
+
+= 実験原理
+NPN型トランジスターの構造は以下に示す図1のようになっている.左からEがエミッター,Bがベース,Cがコレクターと呼ばれる.NPNトランジスターは以下のような仕組みで増幅作用を得る.
+まず,それぞれの要素の電位がC>B>Eとなるようにする.すると,C>Bの電位であるので,BからCへの電流は流れることができない.Cからの電流はN型半導体からP型半導体への電流であって,整流ダイオードの逆方向の電流になるので,微小電流しか流れない.
+ところが,BからEへの伝習はP型半導体からN型半導体への電流であって,整流ダイオードの順方向の電流になるので,わずかな電位差で電流が流れる.
+しかも,この電流を流すエミッターの中の電子は,更に電位の高いコレクターに電場によって引かれ,大部分がコレクターに注入される.
+BE間の電位差を小さくすると,BE間の電流が小さくなり,コレクターに注入される電子も少なくなる.
+以上から,BE間の僅かな電圧の変化でコレクター電流を大幅に変化させることができる.
diff --git a/typst_feedback_dataset.jsonl b/typst_feedback_dataset.jsonl
@@ -0,0 +1,3 @@
+{"instruction": "#set text(lang: \"ja\", font: \"Noto Sans CJK JP\", size: 10.5pt)\n#set par(leading: 1.5em)\n#set heading(numbering: \"1.\")\n#show heading: set block(below: 1em)\n#set math.equation(numbering: \"(1)\")\n\n#show figure.where(\n kind: table\n): set figure.caption(position: top)\n\n#import \"@preview/muchpdf:0.1.0\": muchpdf\n\n#show regex(\"[\\p{scx:Han}\\p{scx:Hira}\\p{scx:Kana}]\"): set text(font: \"Noto Sans CJK JP\")\n\n#muchpdf(read(\"./titlepage.pdf\", encoding: none),width: 20cm)\n\n#counter(page).update(0)\n#set page(numbering: \"- 1 -\")\n\n#let phisics_experiment_table(header, cells) = {\n table(\n columns: header.len(),\n table.hline(),\n table.header(..header.flatten()),\n table.hline(),\n ..cells,\n table.hline(),\n )\n}\n\n= 実験目的\n直流抵抗と自己インダクタンスとを直列に接続した回路であるインピーダンスダイアグラムを作り,遅れの角および自己インダクタンスを算出すること.\n\n= 実験原理\n直流抵抗(抵抗値$R$Ω)と自己インダクタンス($H$L)を直列に接続したインピーダンスダイアグラムがあるとする.これに電圧$V$Vの直流電流を流したとき,流れる定常電流を$i$Aとするとオームの法則により抵抗値のRが次式より求まる.\n$ R = V/i $\nまたこれに周波数$nu$Hzの交流電流($V=V_0 sin(2 pi nu t)$流すと,一般化されたオームの法則から$V - L (d i)/(d t) = R i$(ここで$i$は流れている電流)であるので次式が成り立つ.\n$ L (d i)/(d t) + R i = V_0 sin(2 pi nu t) $\nこの式の解を最大電流$i_0$と遅れの角$phi$を使って$i = i_0 sin(2 pi nu t - phi)$と書けると仮定すると,これを上式に代入して,最大電流$i_0$と遅れの角$phi$は以下のように決定される.\n$ cases(\n i_0 = V_0/sqrt(R^2+4 pi^2 nu^2 L^2),\n phi = tan^(-1)((2 pi nu L)/R)\n) $\nここで,$V_e, i_e$をそれぞれ有効電圧,実行電圧とすると,\n$ sqrt(R^2 + 4 pi^2 nu^2 L^2) = V_0/i_0 = V_e/i_e $\nが成り立つ.上記から交流電圧計と交流電流計を用いてインピーダンス($sqrt(R^2 + 4 + pi^2 nu^2 L^2)$)を求めることができる.\n直流電圧流したときの結果より直流抵抗の抵抗値$R$,交流電圧を流したときの結果よりインピーダンス$sqrt(R^2 + 4 + pi^2 nu^2 L^2)$を求められれば,$2 pi nu L$の値が求められる.\n従って遅れの角$phi$を算出することができ,周波数計により交流周波数を測定すると自己インダクタンス$L$を求めることができる.\n\n= 実験方法\n実験装置:直流電源・スライダック・鉄心入りコイル・直流電流計・直流電圧計・交流電流計・交流電圧計・可変抵抗\n\nまず実験装置を用いて回路を作った.\n直流の回路は図1,交流の回路図2に示すような回路にした.\n#figure(\n kind: image,\n caption: [直流回路],\n image(\"./dccircit.png\"),\n)\n#figure(\n kind: image,\n caption: [交流回路],\n image(\"./accircit.png\"),\n)\n\n== 直流回路の測定\n1. 可変抵抗の値をできるだけ小さくした.\n2. 直流電源のツマミを0にして,プラグを接続して電源を入れた.\n3. 電流値が0.1Aになるように,VOLTAGEのつまみをまわし,次にCURRENTのつまみを回して定電流を流した.\n4. 電流計・電圧計の数値が安定しないときは,可変抵抗の値を少しだけ大きくし,再度電流が0.1Aになるように定電流を流した.\n5. 値が安定したら,そのときの電流計と電圧計の値を測定した.\n6. 4から5の操作を電流が0.1Aから1.0Aまで0.1Aづつ増加させて計測した.\n\n== 交流回路の測定\n1. 直流回路から電源・電流計・電圧計だけを変更し,その他は動かさないように回路を組み替えた.\n2. スライダックのつまみを0にして,プラグを接続した.\nここで,交流電源にはコンセントから給電したスライダックを用いたそのため,周波数は西日本のコンセントの周波数である60Hzになった.\n3. スライダックのつまみを回し,電流計の値が0.1Aになるように電流を流した.\nスライダックはつまみを0にしていてもオフセット電流が流れる.オフセット電流が0.1Aよりも大きい場合はそれを1つ目の測定値とした.\n4. 値が安定したら,その時の電流計と電圧計の値を測定した.\n5. 3から4の操作を電流が0.1Aから1.0Aまで0.1Aづつ増加させて測定した.\n\n= 結果\n直流回路により,得られた値を表1に示す.\n#figure(\n kind: table,\n caption: [直流回路のI-V特性],\n phisics_experiment_table(\n (\"測定番号\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"合計\"),\n csv(\"current.csv\").flatten(),\n )\n)\n\n交流回路により,得られた値を表2に示す.\n#figure(\n kind: table,\n caption: [交流回路のI-V特性],\n phisics_experiment_table(\n (\"測定番号\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"合計\"),\n csv(\"voltage.csv\").flatten(),\n )\n)\n以上の結果より,最小二乗法を用いて,それぞれの回路のI-V特性を求めた.\n直流回路について\n$ V = R I + V_0_r $とすると\n$ V = 7.777576 I + 0.177333 $\nなので,\n$ R = (777 plus.minus 6) times 10^(-2) [\"Ω\"] $\n$ V_0_r = (17 plus.minus 4) times 10^(-2) [\"Ω\"] $\nまた,交流回路について\n$ V = Z I + V_0_z $\n$ V = 14.5697 I - 0.07333 $\nしたがって,\n$ Z = (145 plus.minus 3) times 10^(-1) [\"Ω\"] $\n$ V_0_z = (0 plus.minus 2) times 10^(-1) [\"Ω\"] $\n\nこれにより,自己インダクタンス$L$とその誤差$sigma_L$は,\n$ Z^2 = R^2 + 2 pi^2 nu^2 L^2 $\nより\n$ L = sqrt(Z^2 - R^2)/(2 pi nu) = 3.2680 times 10^(-2) [\"Ω\"] $\n$ sigma_L = 1/(2 pi nu sqrt(Z^2-R^2)) sqrt(Z^2 (sigma_Z)^2 - R^2 (sigma_R)^2) = 8.5 times 10^(-4) [\"Ω\"] $\n$ L = (327 plus.minus 9) times 10^(-4) [\"Ω\"] $\nそれにより,遅れの角$phi$とその誤差$sigma_phi$は,\n$ phi = tan^(-1)((2 pi nu L)/R ) = 1.007686... [\"rad\"] $\n$ sigma_phi = (2 pi nu)/(4 pi^2 nu^2 L^2 + R^2) sqrt(R^2 (sigma_R)^2 + L^2 (sigma_L)^2) [\"rad\"] $\n$ phi = (57 plus.minus 5 ) times 10 [°] $\n\n= 考察\n実験より,回路に用いた鉄心入りコイルのリアクタンス$L$は,\n$ L = (327 plus.minus 9) times 10^(-4) [\"Ω\"] $\nまた,遅れの角$phi$は,\n$ phi = (57 plus.minus 5 ) times 10 [°] $\nであると求まった.\nリアクタンスの相対誤差は,$9/327 = 0.027522... tilde.eq.rev 3%$\n遅れの角の相対誤差は$5/57 = 0.087719... tilde.eq.rev 9%$\nである.この値より,十分な精度は出ていないといえる.\n特に交流の0.1Aに関しては,以下の追加課題で示すグラフを見ると,他の測定点に対して一直線上から離れた点を示している.この点を除いて計算をし直すと,\n$ L' = (316 plus.minus 6) times 10^(-4) [\"Ω\"] $\n$ phi' = (56 plus.minus 5 ) times 10 [°] $\nとなり,Lの相対誤差は$6/316 = 0.0189... tilde.eq.rev 2%$\nphiの相対誤差は$5/56 = 0.0847400... tilde.eq.rev 8%$\nであり,数値が少し改善した.\nこの測定の誤差が大きくなった原因として,測定をするときに電流と電圧がなかなか安定しておらず,不安定なまま測定を行ってしまい,測定の精度が低下したことが考えられる.\n\n== 追加課題について\n=== 設問1\n以下の図3に作成したインピーダンスダイヤグラムを示す.\n#figure(\n kind: image,\n caption: [作成したインピーダンスダイヤグラム],\n image(\"2025111901.jpg\"),\n)\n\n=== 設問2\n三角形ABCは円に内接しており,ACはその円の中心を通っている.これとタレスの定理より,この三角形ABCは角Bが直角であることが分かる.\nピタゴラスの定理より,\n$ R^2 = \"AB\"^2 + Z^2 $\n$ R^2 = \"AB\"^2 + R^2 + 4 pi^2 nu^2 L^2$\n$ \"AB\"^2 = 4 pi^2 nu^2 L^2 $\n$ \"AB\" = 2 pi nu L $\nよって$\"AB\" = 2 pi nu L$が示された.\n\n=== 設問3\n以下に測定値とその誤差を示す.\nただし,器械的誤差は最小メモリ0.01cmなので,0.005cmとすべきだが,有効数字が足りないので,0.01cmとしている.\n$ \"AC(Z)\" = 14.50 plus.minus 0.01 [\"cm\"] $\n$ \"CD(R)\" = 7.95 plus.minus 0.01 [\"cm\"] $\n$ \"AB\" = 12.16 plus.minus 0.01 [\"cm\"] $\n$\"AB\" = 2 pi nu L$より$L = \"AB\" / (2 pi nu)$より,\n$ L = 0.03225 plus.minus 0.00001 [\"Ω\"] $\n\n=== 設問4\n今回の実験で可変抵抗をできるだけ小さくした理由は,もし可変抵抗を大きくすると,\n$ Z = sqrt(R^2 + (4 pi^2 nu^2 L^2)) $\nの$R^2$の項が大きくなるので,リアクタンスの含まれる項の影響が相対的に小さくなってしまい,誤差が大きく出てしまうから.\n\n= 参考文献\n[1] 吉田卯三郎 他著 (三省堂) P.257\n", "output": "[{\"type\":\"format\",\"location\":\"全体\",\"text\":\"数字の後の単位には [ ] を使用しないでください。記号の後の単位の表記についても確認してください。\"},{\"type\":\"format\",\"location\":\"図1, 図2\",\"text\":\"回路図記号のチルダ(~)は記号の下に配置してください。\"},{\"type\":\"detail\",\"location\":\"交流回路の測定, 3.\",\"text\":\"交流回路の測定において、オフセット電流が実際にどの程度だったのか、そしてそれに対してどのような対応を取ったのかを具体的に記述してください。\"},{\"type\":\"methodology\",\"location\":\"結果\",\"text\":\"最小二乗法などの解析に用いたデータやグラフの「解析用の欄」(例:軸の範囲、データ点など)を示したことについても記述してください。\"},{\"type\":\"logic\",\"location\":\"結果, 最小二乗法の結果の式\",\"text\":\"最小二乗法によるフィッティング結果の残差について言及するならば、その式も記述した方が良いでしょう。または、$V_0_r$や$V_0_z$のような切片項の意味を明確にしてください。\"},{\"type\":\"methodology\",\"location\":\"結果\",\"text\":\"最小二乗法の計算式と計算過程を詳細に記述してください。\"}]"}
+{"instruction": "#set text(lang: \"ja\", font: \"Noto Sans CJK JP\")\n#set par(leading: 1.5em)\n#set heading(numbering: \"1.\")\n#show heading: set block(below: 1em)\n#set math.equation(numbering: \"(1)\")\n\n#show figure.where(\n kind: table\n): set figure.caption(position: top)\n\n#import \"@preview/muchpdf:0.1.0\": muchpdf\n\n#show regex(\"[\\p{scx:Han}\\p{scx:Hira}\\p{scx:Kana}]\"): set text(font: \"Noto Sans CJK JP\")\n\n#muchpdf(read(\"./titlepage.pdf\", encoding: none),width: 20cm)\n\n#counter(page).update(0)\n#set page(numbering: \"- 1 -\")\n\n#let phisics_experiment_table(header, cells) = {\n table(\n columns: header.len(),\n table.hline(),\n table.header(..header.flatten()),\n table.hline(),\n ..cells,\n table.hline(),\n )\n}\n\n= 実験目的\n分光計により,波長の分かっている単色光を用いて回折格子の定数(1cm当たりのミゾの本数)を決定すること。\n\n= 実験原理\n回折格子に特定の周波数の光を当てると、特定の方向にのみ光が強く出る。\nその原理は、以下である。\n格子定数nの回折格子があるとする。この回折格子に対して垂直に入射する波長$lambda$の平行光線を入射する。この平行光線が入射方向に対して$phi$だけずれたとすると、平行に出射する光線との経路差は$1/n sin(phi)$となる。したがって、\n$ 1/n sin(phi) = m lambda (m in NN) $\nを満たす$phi$の方向の光の強度が最大になることがわかる。\nこれを用いて、回折格子に特定の周波数の光を当て、強く光が出る方向を測定することで、その回折格子の格子定数を求めることができる。\n\n= 実験方法\n実験装置:分光計・ガラス製回折格子・光源(ナトリウムランプ)\n\nこの実験は以下の手順に従って、暗室で行った。\n分光計の副尺の読み取りは二箇所の値を読み取り、平均化した値を取った。\n\n1. 望遠鏡の調整\n分光計についている望遠鏡を外し、遠くのものを見て、焦点を合わせた。\n2. 分光計の調整\n望遠鏡の視軸を分光計の回転軸に垂直にし、かつ回折格子の表面を望遠鏡の視線に垂直にした。\nまた、コリメーターから出る光を平行にし、その視軸を望遠鏡の視軸と並行にした。\n3. 光源の設置\nスリットの望遠鏡と反対側に光源としてナトリウムランプを置き、ナトリウムランプの電源スイッチを入れると黄色い光が発せられることを確認した。\nまた、望遠鏡とコリメーターを同一光軸上に置き、スリットの像が明るくなるように光源の位置を微調整した。\n4. スリットの調整\n望遠鏡を見ながらスリット幅をなるべく細くした。\n5. 回折格子の設置\nコリメーターからの光が回折格子の表面に垂直に入射するように、回折格子を分光計に設置した。\n回折格子の透過光の中心に望遠鏡Tの十字線を合わせて、その読み取り盤の値を読み取り、0次線の角度とした。\n6. n次線の探索\n望遠鏡を上から見て反時計方向(または時計方向)に回転しながら、スリットの像を探した。\nはじめに見つけたスリットの像は-1次(または+1次)の回折戦で形成された像とし、この回折像の中央に4と同様に十字線の中央を合わせ、その時の角度を読み取った。\nさらに同じ方向に回転させて次の回折像を見つけ、同様な測定を-5次(+5次)まで行った。\n\n= 結果\n=== 測定値\n分光計によって得た、光の像の強まる角度を以下にまとめた。\n#figure(\n caption: [光の強まる角度],\n kind: table,\n phisics_experiment_table(\n ([項目],[5次],[4次],[3次],[2次],[1次],[0次],[-1次],[-2次],[-3次],[-4次],[-5次],),\n csv(\"./v.csv\").flatten(),\n )\n)\n=== 測定値の解析\nまた、$theta$から$phi$を求めたものを以下にまとめた。\n#figure(\n caption: [$theta$による$phi$の値],\n kind: table,\n phisics_experiment_table(\n ([],[1次],[2次],[3次],[4次],[5次]),\n csv(\"phi.csv\").flatten(),\n )\n)\n次に得られた$phi$の値を元に、それぞれの次数でのnの最確値を求める。\n次数mにおけるnの最確値の式は原理より以下であることが分かる。\n$ n = sin(phi) / (m lambda) $\nここで、ナトリウムランプから発せられる光の波長を教科書[1]より$5.893 times 10^(-5)$とすると、\n$ n = (sin (phi) / m times 5.893) times 10^5 (本)$と分かる。これらを1~5次までに適応すると、\n#let phis = (\"1\":\"1011.1\",\"2\":\"999.8\",\"3\":\"1001.7\",\"4\":\"998.8\",\"5\":\"995.1\")\n#for (m,o) in phis [\n$ n_(#m) = (sin(phi) / (m times 5.893)) times 10^5= #o (本) $\n]\n\nとなる。この結果をまとめると、\n#figure(\n caption: [次数による$theta$の値],\n kind: table,\n phisics_experiment_table(\n ([次数],[1次],[2次],[3次],[4次],[5次]),\n ([n (本)],[1011.1],[999.8],[1001.7],[998.8],[995.1]),\n )\n)\n=== 誤差論\n次にnの偶然誤差について考える。\nnの偶然誤差である$d^2$平均($d := n - $average$(n)$)は、以下の表によって求まる。\n#figure(\n caption: [nの偶然誤差],\n kind: table,\n phisics_experiment_table(\n ([次数],[1],[2],[3],[4],[5],[平均]),\n csv(\"./n-d.csv\").flatten(),\n )\n)\n次にそれぞれの次数における、測定値の誤差によるnへの影響を考える。\n$ phi = (V_1 + (V')_1)/2 - (V_2 + (V')_2)/2 $\nこれを式(2)に代入すると、\n$ n = (sin((V_1 + (V'_1))/2 - (V_2 + (V'_2))/2)/(m lambda)) $\nこれについて1~5次まで誤差の計算を行う。\nなお、分光計の機械的誤差は0.5分なので角度に直すと$1/120$°となる。\n1次について\n$ delta_n_1 = sqrt(((diff n)/(diff V_1))^2 delta^2_(V_1) + ((diff n)/(diff V'_1))^2 delta^2_(V'_1) + ((diff n)/(diff V_2))^2 delta^2_(V_2) + ((diff n)/(diff V'_2))^2 delta^2_(V'_2)) $\nルート内の各項は同様の値を持つので、以下は第一項を4倍した値として扱う。\n$ delta_n_1 = sqrt(4 times ((diff n)/(diff V_1))^2 delta^2_(V_1)) $\n$phi_1$を一次における$phi$の最確値とすろと、\n$ delta_n_1 = sqrt(4 times (1/(2 m lambda) cos(phi))^2 delta^2_(V_1)) = sqrt((1/(m times 5.893) times 10^5 times cos(phi) )^2 (1/120)^2) $\n$ = sin(phi_1) / (m times 5.893 times 120) times 10^5 = 141.115... [本] $\n#let deltas = (\"2\":\"70.212\",\"3\":\"46.3919\",\"4\":\"34.359\",\"5\":\"27.039\")\n#for (m,delta) in deltas [\n同様にして#m 次は\n$ delta_n_#m = sin(phi_#m) / (#m times 5.893 times 120) times 10^5 = #delta... (本) $\n]\n\n= 考察\n実験より、$n = 1.00 times 10^4 plus.minus 2.8 times 10 [本]$という結果を得た。\nこの相対誤差は、$(2.8 times 10)/(1.00 times 10^4) = 2.8%$であった。これにより、ある程度の精度をもって測定することができた。\nまた、この誤差の範囲内に、用いた格子の値である$n=1000$は収まっている。\n次に、それぞれの次数でのnの機械的誤差と相対誤差は以下の表のようになっている。\n#figure(\n caption: [次数によるnの機械的誤差],\n kind: table,\n phisics_experiment_table(\n ([次数],[1],[2],[3],[4],[5]),\n csv(\"./diffn.csv\").flatten(),\n )\n)\nこの表から次数が上がるとnの誤差が小さくなっていることがわかる。これはnの式にある次数であるmが分母にあるためであると考えられる。\nまた、いずれの結果もnの真値である$n=1000$が誤差の範囲内に含まれていることがここからも確認できる。\n\n= 参考文献\n[1] 吉田卯三郎 他著 (三省堂) P.176\n", "output": "[{\"type\":\"detail\",\"location\":\"全体\",\"text\":\"気圧は0.1の位まで記載してください。\"},{\"type\":\"logic\",\"location\":\"実験原理\",\"text\":\"実験原理の説明が不足しています。より詳細な説明が必要です。\"},{\"type\":\"clarity\",\"location\":\"実験方法\",\"text\":\"実験装置の図がないため、他人が実験を再現できるか不明です。図の追加を検討してください。\"},{\"type\":\"clarity\",\"location\":\"実験方法, 1. 望遠鏡の調整\",\"text\":\"望遠鏡のピント(焦点)を具体的にどのように合わせたのか説明が必要です。\"},{\"type\":\"clarity\",\"location\":\"実験方法, 2. 分光計の調整\",\"text\":\"コリメーターのピント調整について説明がありません。詳細を追加してください。\"},{\"type\":\"format\",\"location\":\"全体\",\"text\":\"表の説明文は「表◯に~~を示す」のように、表の番号を含めて記述してください。\"},{\"type\":\"format\",\"location\":\"結果, nの最確値の式\",\"text\":\"ナトリウムランプから発せられる光の波長の値に単位がありません。単位を追記してください。\"},{\"type\":\"format\",\"location\":\"結果, 3つ目の表 (caption: [次数による$theta$の値])\",\"text\":\"表3のタイトルが内容と一致していません。現在のタイトルは「次数による$theta$の値」ですが、内容はnの値です。修正してください。\"},{\"type\":\"format\",\"location\":\"結果, 4つ目の表 (caption: [nの偶然誤差])\",\"text\":\"表4の単位が不足しています。適切な単位を追記してください。\"},{\"type\":\"content\",\"location\":\"結果, 4つ目の表 (caption: [nの偶然誤差])\",\"text\":\"表4に合計値も記載してください。\"},{\"type\":\"analysis\",\"location\":\"結果, 誤差論\",\"text\":\"5つのnの偶然誤差について、具体的な計算や考察が不足しています。詳細を追加してください。\"},{\"type\":\"format\",\"location\":\"考察\",\"text\":\"最終的な結果(nの値)を「最確値±誤差」の形式で表記してください。\"},{\"type\":\"clarity\",\"location\":\"結果, 誤差論\",\"text\":\"偶然誤差の計算方法について、より詳細な説明が必要です。\"},{\"type\":\"format\",\"location\":\"考察, n = 1.00 times 10^4 plus.minus 2.8 times 10 [本]\",\"text\":\"「最確値±誤差」の表記において、べき乗は全体にかかるように括弧でくくり、それぞれにべき乗をつけないでください(例:$(1.00 \\times 10^4 \\times \\text{本}) \\times (1 \\times 10^4 \\times \\text{本})$)。\"},{\"type\":\"analysis\",\"location\":\"考察\",\"text\":\"考察において、nの測定精度がどうなるか、またどのような次数で測定すべきかについて、より深い分析と結論を述べてください。\"}]"}
+{"instruction": "#set text(lang: \"ja\", font: \"Noto Sans CJK JP\")\n#set par(leading: 1.5em)\n#set heading(numbering: \"1.\")\n#show heading: set block(below: 1em)\n#set math.equation(numbering: \"(1)\")\n\n#show figure.where(\n kind: table\n): set figure.caption(position: top)\n\n#import \"@preview/muchpdf:0.1.0\": muchpdf\n\n#show regex(\"[\\p{scx:Han}\\p{scx:Hira}\\p{scx:Kana}]\"): set text(font: \"Noto Sans CJK JP\")\n\n#muchpdf(read(\"./titlepage.pdf\", encoding: none),width: 20cm)\n\n#counter(page).update(0)\n#set page(numbering: \"- 1 -\")\n\n#let phisics_experiment_table(header, cells) = {\n table(\n columns: header.len(),\n table.hline(),\n table.header(..header.flatten()),\n table.hline(),\n ..cells,\n table.hline(),\n )\n}\n\n= 実験目的\nナトリウムランプから発せられる単色光によるニュートンリングを作るレンズの曲率半径を測定すること。\n\n= 実験原理\n平行ガラス板BB′上に曲率半径Rの非常に大きな平凸レンズAA′を置いたとし、波長λの単色光をこれに垂直に入射させる。この場合、空気層ABまたはA′B′は、きわめて薄いと考えられるので、入射光も反射光もほぼ平行とみなすことができる。\nしたがって、空気層の上面AA′からの反射光と、下面BB′からの反射光との光路差を求めるには、\n$ A B = A'B' = O D = z, A D = A'D' = r, E D = 2R-z $\nとすると、\n$ r^2 = (2R-z)z = 2R z - z^2 tilde.equiv 2R z $\nこれに加えて、AA'からの反射光は密から疎な媒質への境の反射であり、BB'からの反射光は疎から密への境の反射であるので、経路差とすべきのは上式から導かれる光路差に半波長を足したものであると考えられる。\nこれらを踏まえて全光路差は$2z+ lambda/2$であることが分かる。\nしたがって、m番目のr、$r_m$に成り立つ関係式は\n$ r^2_m = m lambda R ( m in NN ) $\nだと分かる。この式から次を考えると、\n$ r^2_m - r^2_(m + n) = n lambda R (m,n in NN) $\n故に\n$ R = (r^2_m - r^2(m+n))/(n lambda) $\nが求まる。\n以上より、m本目とm+n本目のニュートンリングの直径を測定することで、Rを間接的に測定することができる。\n\n= 実験方法\n実験器具:ニュートンリング測定装置、ナトリウムランプ、集光レンズ\n\nこの実験は以下の手順に従って、暗室で行った。\n数値の測定はマイクロメーターによって行った。\nまた、実験器具の配置と光の経路を図1に示した。\n#figure(\n caption: [実験器具の配置と光の経路],\n kind: image,\n image(\"fig1.jpg\"),\n)\n\n1. 実験器具の配置\nニュートンリング測定装置を設置する。その正面にナトリウムランプを設置する。ニュートンリング測定装置とナトリウムランプの間に集光レンズを設置し、ニュートンリング測定装置へ入射する光が平行な光になるようにする。\n\n2. 器具の調整\nナトリウムランプの電源をつけ、ニュートンリング測定装置についている遊動顕微鏡を覗く。\nニュートンリングが見えたらばピント合わせ、半透明反射鏡を傾けて、ニュートンリングが明るく見えるように調節する。\n\n3. 最初の位置合わせ\nニュートンリングの中心を遊動顕微鏡の十字線の軌跡が通過するようにリングの取り付けネジを調整しリングの中心を移動させる。この場合にニュートンリングが真円からずれないように注意をする。\n\n4. 測定\nm番目の暗輪(または明輪)に遊動顕微鏡の十字線を合わせて、マイクロメーターでその時の値を読み取る。\n次に、m-1番目の暗輪(または明輪)に遊動顕微鏡の十字線を合わせてそのときの値を読み取る。\n同様な測定を-m番目まで行う。ここでmの値は10以上とし、0番目のリングの測定も忘れないように行う。\nここで移動機構の遊びを避けるため、移動方向を途中で反転させないように気をつける。\n\n\n= 結果\n=== 測定値\n測定で得た、m番目のニュートンリングの値を表1にまとめた。\nなお、$m$が負のものは$(a_m)'$として表にまとめている。\n#figure(\n caption: [ニュートンリングの位置],\n kind: table,\n phisics_experiment_table(\n (\"m\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\"),\n csv(\"a_m.csv\").flatten(),\n ),\n)\n=== 測定値の解析\nまた、上記の値から$R$の値を求めた。\nmとnの値は次のように選んだ。\nnが大きいとき、小さいサイズのリングから大きいサイズのリングまでを取ることができ、レンズに歪みがあった場合に平均的な曲率半径を取ることができると考えた。\n逆に、$n=1$と極端に小さくしたときは局所的な曲率半径を求めることができるので、$m=1,m=5,m=9$のときについてそれぞれ曲率半径Rを求めた。\nただし、ナトリウムランプから発せられる単色光の波長は参考文献[1]より、$5.893 times 10^(-7)$の値を用いた。\n==== Case: m=1 n=9\n$ R = ((a_10 - a's_10)^2 - (a_1 - a'_1)^2)/(4 times 9 times lambda) = ((7.224 times 10^(-3))^2 times (5.55 times 10^(-3))^2)/(4 times 9 times lambda) $\n$ = ((52.19-6.503)times 10^(-6))/(4 times 9 times lambda) = (4.56837 times 10^(-6))/(4 times 9 times 5893 times 10^(-10)) = 2.1534 (m) $\n\n==== Case: m=1 n=1\n$ R = ((a_2 - a's_2)^2 - (a_1 - a'_1)^2)/(4 times 1 times lambda) = ((3.417 times 10^(-3))^2 times (2.55 times 10^(-3))^2)/(4 times 1 times lambda) $\n$ = ((1.168-0.065025)times 10^(-6))/(4 times 1 times lambda) = (5.17339 times 10^(-6))/(4 times 1 times 5893 times 10^(-10)) = 2.1947 (m) $\n\n==== Case: m=5 n=1\n$ R = ((a_6 - a's_6)^2 - (a_5 - a'_5)^2)/(4 times 1 times lambda) = ((5.613 times 10^(-3))^2 times (5.144 times 10^(-3))^2)/(4 times 1 times lambda) $\n$ = ((3.151-2.646)times 10^(-6))/(4 times 1 times lambda) = (5.045 times 10^(-6))/(4 times 1 times 5893 times 10^(-10)) = 2.1403 (m) $\n\n==== Case: m=9 n=1\n$ R = ((a_10 - a's_10)^2 - (a_9 - a'_9)^2)/(4 times 1 times lambda) = ((7.24 times 10^(-3))^2 times (6.869 times 10^(-3))^2)/(4 times 1 times lambda) $\n$ = ((5.129-4.718)times 10^(-6))/(4 times 1 times lambda) = (5.003 times 10^(-6))/(4 times 1 times 5893 times 10^(-10)) = 2.1224 (m) $\n\n==== Rの偶然誤差\n上記で求めた曲率半径の偶然誤差を計算した表を以下に示す。\n#figure(\n caption: [求めたRの偶然誤差],\n kind: table,\n phisics_experiment_table(\n (\"n,m\",\"m=1,n=9\",\"m=1,n=1\",\"m=5,n=1\",\"m=9,n=1\",\"平均値\"),\n csv(\"r.csv\").flatten(),\n ),\n)\n以上から、誤差は$7.1 times 10^(-4)$と求まった。\n\n= 考察\n実験から、曲率半径Rは$R = 2.1527 plus.minus 7 times 10^(-4)$と求まった。また、Rの相対誤差は3%と求まった。\nまた、$n=1$のときのmと曲率半径Rの関係としては、mが大きくなるほどRが小さな値になる傾向が見られた。\nこの原因として考えられるのは、レンズの固定のためにレンズの縁をネジで押し付けて固定しているため、レンズの縁に曲率と逆の向きに圧力がかかっていることが考えられる。\nまた、リングの次数が上がるにつれ、縁に近いことやレンズの厚さが増すことで、圧力による曲率の変化が縁に近づくにつれて大きくなっている事が考えられる。\nこれを概念的に図示すると以下の図のようになる。\n#figure(\n caption: [レンズの歪み方の概念図],\n kind: image,\n image(\"fig2.jpg\"),\n)\n\n\n= 参考文献\n[1] 吉田卯三郎 他著 (三省堂) P.182\n", "output": "[{\"type\":\"metadata\",\"location\":\"全体\",\"text\":\"レポートのファイル名に関する情報が不足しています。\"},{\"type\":\"metadata\",\"location\":\"実験方法\",\"text\":\"実験場所(例:研究室名、部屋番号)が記載されていません。\"},{\"type\":\"clarity\",\"location\":\"実験原理\",\"text\":\"実験原理の説明に図がないため、ニュートンリングの形成メカニズムや光路差の導出が視覚的に理解しにくいです。\"},{\"type\":\"method\",\"location\":\"実験方法 2. 器具の調整\",\"text\":\"ニュートンリングのピント合わせについて、具体的な調整方法(例:どのネジをどのように動かしたか)が不明です。\"},{\"type\":\"grammar\",\"location\":\"実験方法\",\"text\":\"実験方法の記述が「行った」「した」などの過去形になっています。一般的に、実験レポートの方法は現在形または未来形(~する)で記述します。\"},{\"type\":\"clarity\",\"location\":\"実験方法 3. 最初の位置合わせ\",\"text\":\"「リングの取り付けネジ」が図1のどの部分を指すのか、図中に明記されていないため分かりにくいです。\"},{\"type\":\"method\",\"location\":\"実験方法 4. 測定\",\"text\":\"移動機構の遊びを避けるため「移動方向を途中で反転させないように気をつける」とありますが、具体的にどのような手順で測定を行ったのか(例:一方向にのみ移動させた、測定順序など)が不明です。\"},{\"type\":\"logic\",\"location\":\"測定値の解析\",\"text\":\"n=1のケースでmを1, 5, 9と選んだ理由について、説明が不足しており、読者が意図を理解しにくいです。\"},{\"type\":\"format\",\"location\":\"Rの偶然誤差 (表2)\",\"text\":\"表2「求めたRの偶然誤差」の数値が指数表記(Eを使った書き方)で記載されており、読みにくいです。一般的な数値表記に修正してください。\"},{\"type\":\"calculation\",\"location\":\"Rの偶然誤差\",\"text\":\"曲率半径Rの偶然誤差を計算したとありますが、その計算式と具体的な計算過程が記載されていません。\"},{\"type\":\"clarity\",\"location\":\"考察 (図2)\",\"text\":\"図2「レンズの歪み方の概念図」が、mが大きくなるほどRが大きくなるように見えます。しかし、考察では「mが大きくなるほどRが小さな値になる傾向が見られた」とあり、図と考察の内容が矛盾しているように見えます。図の表現を修正するか、説明を補足してください。\"}]"}
diff --git a/vendor/llama.cpp b/vendor/llama.cpp
@@ -0,0 +1 @@
+Subproject commit 3d94e967a10ac901392c6abc8747aed204a09bdb