Skip to content

Commit

Permalink
Add analyze
Browse files Browse the repository at this point in the history
  • Loading branch information
tansongchen committed Jun 28, 2024
1 parent 15b2125 commit 9b8d9e0
Showing 1 changed file with 163 additions and 63 deletions.
226 changes: 163 additions & 63 deletions src/pages/[id]/statistics.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Flex, Table } from "antd";
import { Flex, Select, Table } from "antd";
import {
alphabetAtom,
displayAtom,
frequencyAtom,
repertoireAtom,
sequenceAtom,
useChaifenTitle,
} from "~/atoms";
import {
Expand All @@ -14,11 +16,9 @@ import {
} from "@ant-design/pro-components";
import { Form, Space, Typography } from "antd";
import { useAtomValue } from "jotai";
import type { Frequency } from "~/atoms";
import { maxLengthAtom } from "~/atoms";
import type { AnalyzerForm, AssemblyResult } from "~/lib";
import type { AnalyzerForm, AssemblyResult, Frequency } from "~/lib";
import { renderIndexed } from "~/lib";
import { Select } from "~/components/Utils";
import { useState } from "react";
import { assemblyResultAtom } from "~/atoms/cache";
import type { ColumnsType } from "antd/es/table";
Expand All @@ -45,6 +45,7 @@ const analyzePrimitiveDuplication = (
result: AssemblyResult,
display: (d: string) => string,
maxLength: number,
replacer: (d: string) => string = (d) => d,
) => {
const reverseMap = new Map<string, string[]>();
let relevant = result;
Expand All @@ -59,11 +60,11 @@ const analyzePrimitiveDuplication = (
relevant = relevant.slice(0, analyzer.top);
}
for (const assembly of relevant) {
const { name, sequence: elements } = assembly;
const { name, sequence } = assembly;
const sliced = range(maxLength).map((i) =>
analyzer.position.includes(i) ? elements[i] : "*",
analyzer.position.includes(i) ? sequence[i] : "*",
);
const summary = `(${sliced.map((x) => renderIndexed(x, display)).join(", ")})`;
const summary = `(${sliced.map((x) => replacer(renderIndexed(x, display))).join(", ")})`;
reverseMap.set(summary, (reverseMap.get(summary) || []).concat(name));
}

Expand All @@ -75,11 +76,76 @@ interface Density {
items: string[];
}

const AnalyzerConfig = ({
analyzer,
setAnalyzer,
}: {
analyzer: AnalyzerForm;
setAnalyzer: (a: AnalyzerForm) => void;
}) => {
const [form] = Form.useForm<AnalyzerForm>();
const maxLength = useAtomValue(maxLengthAtom);
return (
<ProForm<AnalyzerForm>
form={form}
layout="horizontal"
submitter={false}
initialValues={analyzer}
onValuesChange={(_, values) => setAnalyzer(values)}
autoFocusFirstInput={false}
>
<ProFormGroup>
<ProFormSelect
mode="multiple"
name="position"
label="取码"
options={range(maxLength).map((d) => ({
label: `第 ${d + 1} 码`,
value: d,
}))}
allowClear={false}
/>
<ProFormSelect
name="type"
label="类型"
width="xs"
options={[
{ label: "全部", value: "all" },
{ label: "一字词", value: "single" },
{ label: "多字词", value: "multi" },
]}
/>
<ProFormDependency name={["top"]}>
{({ top }) => (
<Space>
<Form.Item label="范围">
<Select
value={top === 0 ? 0 : 1}
options={[
{ label: "全部", value: 0 },
{ label: "前", value: 1 },
]}
onChange={(value) => {
const top = value === 0 ? 0 : 500;
form.setFieldValue("top", top);
setAnalyzer({ ...form.getFieldsValue(), top });
}}
style={{ width: 96 }}
/>
</Form.Item>
<ProFormDigit name="top" width="xs" disabled={top === 0} />
</Space>
)}
</ProFormDependency>
</ProFormGroup>
</ProForm>
);
};

const SubStatistics = ({ init }: { init: AnalyzerForm }) => {
const maxLength = useAtomValue(maxLengthAtom);
const [analyzer, setAnalyzer] = useState(init);
const [form] = Form.useForm<AnalyzerForm>();
const assemblyResult = useAtomValue(assemblyResultAtom) ?? [];
const assemblyResult = useAtomValue(assemblyResultAtom);
const frequency = useAtomValue(frequencyAtom);
const display = useAtomValue(displayAtom);
const reverseMap = analyzePrimitiveDuplication(
Expand Down Expand Up @@ -127,59 +193,7 @@ const SubStatistics = ({ init }: { init: AnalyzerForm }) => {
<Typography.Title level={3}>
{order}元分布({coorder}阶重码估计:{Math.round(estimation)}
</Typography.Title>
<ProForm<AnalyzerForm>
form={form}
layout="horizontal"
submitter={false}
initialValues={analyzer}
onValuesChange={(_, values) => setAnalyzer(values)}
autoFocusFirstInput={false}
>
<ProFormGroup>
<ProFormSelect
mode="multiple"
name="position"
label="取码"
options={range(maxLength).map((d) => ({
label: `第 ${d + 1} 码`,
value: d,
}))}
allowClear={false}
/>
<ProFormSelect
name="type"
label="类型"
width="xs"
options={[
{ label: "全部", value: "all" },
{ label: "一字词", value: "single" },
{ label: "多字词", value: "multi" },
]}
/>
<ProFormDependency name={["top"]}>
{({ top }) => (
<Space>
<Form.Item label="范围">
<Select
value={top === 0 ? 0 : 1}
options={[
{ label: "全部", value: 0 },
{ label: "前", value: 1 },
]}
onChange={(value) => {
const top = value === 0 ? 0 : 500;
form.setFieldValue("top", top);
setAnalyzer({ ...form.getFieldsValue(), top });
}}
style={{ width: 96 }}
/>
</Form.Item>
<ProFormDigit name="top" width="xs" disabled={top === 0} />
</Space>
)}
</ProFormDependency>
</ProFormGroup>
</ProForm>
<AnalyzerConfig analyzer={analyzer} setAnalyzer={setAnalyzer} />
<Table
dataSource={dataSource}
columns={columns}
Expand All @@ -190,12 +204,98 @@ const SubStatistics = ({ init }: { init: AnalyzerForm }) => {
);
};

const MarginalFirstOrderDuplication = () => {
const assemblyResult = useAtomValue(assemblyResultAtom);
const frequency = useAtomValue(frequencyAtom);
const maxLength = useAtomValue(maxLengthAtom);
const display = useAtomValue(displayAtom);
const sequenceMap = useAtomValue(sequenceAtom);
const repertoire = useAtomValue(repertoireAtom);
const hashedElements = new Set<string>();
for (const { sequence } of assemblyResult) {
sequence.forEach((x) => {
hashedElements.add(renderIndexed(x, display));
});
}
const allElements = [...hashedElements].sort();

const [elements, setElements] = useState(allElements.slice(0, 2));
const [analyzer, setAnalyzer] = useState<AnalyzerForm>({
type: "single",
position: range(0, maxLength),
top: 0,
});

const rmBefore = analyzePrimitiveDuplication(
analyzer,
frequency,
assemblyResult,
display,
maxLength,
);
const szBefore = new Set<string>();
rmBefore.forEach((items) => {
if (items.length > 1) items.forEach((x) => szBefore.add(x));
});
const rmAfter = analyzePrimitiveDuplication(
analyzer,
frequency,
assemblyResult,
display,
maxLength,
(d) => (elements.includes(d) ? "^" : d),
);
const szAfter = new Set<string>();
rmAfter.forEach((items) => {
if (items.length > 1) items.forEach((x) => szAfter.add(x));
});
return (
<>
<Typography.Title level={3}>边际一阶重码计算</Typography.Title>
<AnalyzerConfig analyzer={analyzer} setAnalyzer={setAnalyzer} />
<Flex gap="middle" align="baseline">
<Form.Item label="合并">
<Select
value={elements}
onChange={setElements}
style={{ minWidth: 128 }}
mode="multiple"
options={allElements.map((x) => ({ label: x, value: x }))}
filterOption={(input, option) => {
if (option === undefined) return false;
const value = option.value.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹]/g, "");
if (repertoire[value] !== undefined) {
return sequenceMap.get(value)!.startsWith(input);
} else {
return value.includes(input);
}
}}
filterSort={(a, b) => {
return (
(sequenceMap.get(a.value.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹]/g, "")) ?? "")
.length -
(sequenceMap.get(b.value.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹]/g, "")) ?? "")
.length
);
}}
/>
</Form.Item>
<Typography.Paragraph>
将增加重码:
{[...szAfter].filter((x) => !szBefore.has(x)).join("、")}
</Typography.Paragraph>
</Flex>
</>
);
};

export default function Statistics() {
useChaifenTitle("统计");
const maxLength = useAtomValue(maxLengthAtom);
return (
<Flex vertical gap="middle">
<Typography.Title level={2}>离散性</Typography.Title>
<Typography.Title level={2}>离散性分析</Typography.Title>
<MarginalFirstOrderDuplication />
{range(maxLength, 0).map((x) => {
const type = "single";
return (
Expand Down

0 comments on commit 9b8d9e0

Please sign in to comment.