Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/api/ToolboxAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,40 @@ export async function fetchExampleProblems(problemTypeId: string) {
},
}).then((response) => response.json());
}

export async function fetchProblemBounds(
problemTypeId: string,
problemId: string
) {
return fetch(`${baseUrl()}/problems/${problemTypeId}/${problemId}/bound`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
}).then(
(response) => response.json(),
(reason) => {
return { error: reason };
}
);
}

export async function fetchProblemBoundComparison(
problemTypeId: string,
problemId: string
) {
return fetch(
`${baseUrl()}/problems/${problemTypeId}/${problemId}/bound/compare`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then(
(response) => response.json(),
(reason) => {
return { error: reason };
}
);
}
16 changes: 16 additions & 0 deletions src/api/data-model/BoundComparisonDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { BoundDto, getInvalidBoundDto } from "./BoundDto";
import { getInvalidSolutionObject, SolutionObject } from "./SolutionObject";

export interface BoundComparisonDto {
comparison: number;
bound: BoundDto;
solution: SolutionObject;
}

export function getInvalidBoundComparisonDto(): BoundComparisonDto {
return {
bound: getInvalidBoundDto(),
comparison: 0,
solution: getInvalidSolutionObject(),
};
}
15 changes: 15 additions & 0 deletions src/api/data-model/BoundDto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BoundType } from "./BoundType";

export interface BoundDto {
value: number;
boundType: BoundType;
executionTime: number;
}

export function getInvalidBoundDto(): BoundDto {
return {
value: NaN,
boundType: BoundType.UPPER,
executionTime: -1,
};
}
4 changes: 4 additions & 0 deletions src/api/data-model/BoundType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum BoundType {
UPPER = "UPPER",
LOWER = "LOWER",
}
6 changes: 6 additions & 0 deletions src/api/data-model/ProblemDto.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
BoundComparisonDto,
getInvalidBoundComparisonDto,
} from "./BoundComparisonDto";
import { ProblemState } from "./ProblemState";
import { getInvalidSolutionObject, SolutionObject } from "./SolutionObject";
import { SolverSetting } from "./SolverSettings";
Expand All @@ -8,6 +12,7 @@ export interface ProblemDto<T> {
typeId: string;
input: T;
solution: SolutionObject;
bound: BoundComparisonDto;
state: ProblemState;
solverId?: string;
solverSettings: SolverSetting[];
Expand All @@ -21,6 +26,7 @@ export function getInvalidProblemDto<T>(): ProblemDto<T> {
id: "",
input: {} as T,
solution: getInvalidSolutionObject(),
bound: getInvalidBoundComparisonDto(),
solverId: "",
solverSettings: [],
state: ProblemState.READY_TO_SOLVE,
Expand Down
31 changes: 29 additions & 2 deletions src/components/solvers/Graph/ProblemDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import {
Textarea,
VStack,
} from "@chakra-ui/react";
import { ReactNode } from "react";
import { ReactNode, useState } from "react";
import { ProblemDto } from "../../../api/data-model/ProblemDto";
import { ProblemState } from "../../../api/data-model/ProblemState";
import { fetchProblemBounds } from "../../../api/ToolboxAPI";
import { SettingsView } from "../settings/SettingsView";
import { SolutionView } from "../SolutionView";
import { BoundDisplay } from "../VariableDependentDisplay";
import { useGraphUpdates } from "./ProblemGraphView";
import { useSolvers } from "./SolverProvider";

Expand Down Expand Up @@ -49,6 +51,7 @@ function getAccordionItem(label: string, content: ReactNode) {
export const ProblemDetails = (props: { problemDto: ProblemDto<any> }) => {
const { solvers, getSolvers } = useSolvers();
const { updateProblem } = useGraphUpdates();
const [boundError, setBoundError] = useState(false);

// Update solvers in case they are not loaded yet
if (!solvers[props.problemDto.typeId]) getSolvers(props.problemDto.typeId);
Expand All @@ -57,6 +60,16 @@ export const ProblemDetails = (props: { problemDto: ProblemDto<any> }) => {
(s) => s.id === props.problemDto.solverId
);

function getBound(problemTypeId: string, problemId: string) {
fetchProblemBounds(problemTypeId, problemId).then((res) => {
if (res.error) {
setBoundError(true);
} else {
updateProblem(props.problemDto.id);
}
});
}

return (
<VStack gap="20px" align="start">
<Textarea readOnly resize="vertical" value={props.problemDto.input} />
Expand All @@ -77,6 +90,20 @@ export const ProblemDetails = (props: { problemDto: ProblemDto<any> }) => {
/>
</VStack>
)}
<Text>
<b>Bound: </b>{" "}
{boundError ? (
"Error fetching bound"
) : (
<BoundDisplay
buttonTitle="Get bound"
variable={props.problemDto.bound}
getter={() =>
getBound(props.problemDto.typeId, props.problemDto.id)
}
/>
)}
</Text>
{props.problemDto.subProblems.length === 0 ? (
<b>No subroutines</b>
) : (
Expand All @@ -95,7 +122,7 @@ export const ProblemDetails = (props: { problemDto: ProblemDto<any> }) => {
{props.problemDto.solution !== null && (
<VStack width="100%" align="stretch">
<Text fontWeight="bold">Solution:</Text>
<SolutionView solution={props.problemDto.solution} />
<SolutionView problem={props.problemDto} />
</VStack>
)}
</VStack>
Expand Down
2 changes: 1 addition & 1 deletion src/components/solvers/Graph/ProblemGraphView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ export const ProblemGraphView = (props: ProblemGraphViewProps) => {
nodes[0].data.problemDtos?.length > 0 &&
nodes[0].data.problemDtos[0].state === ProblemState.SOLVED && (
<Flex width="full" ref={solutionViewRef}>
<SolutionView solution={nodes[0].data.problemDtos[0].solution} />
<SolutionView problem={nodes[0].data.problemDtos[0]} />
</Flex>
)}
</VStack>
Expand Down
156 changes: 133 additions & 23 deletions src/components/solvers/SolutionView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@ import {
AccordionPanel,
Box,
Code,
Text,
} from "@chakra-ui/react";
import { SolutionObject } from "../../api/data-model/SolutionObject";
import React, { useState } from "react";
import { ProblemDto } from "../../api/data-model/ProblemDto";
import {
fetchProblemBoundComparison,
fetchProblemBounds,
} from "../../api/ToolboxAPI";
import { useGraphUpdates } from "./Graph/ProblemGraphView";
import {
BoundDisplay,
VariableDependentDisplay,
} from "./VariableDependentDisplay";

export interface SolutionViewProps {
solution: SolutionObject;
problem: ProblemDto<any>;
}

const OutputSection = (props: { title: string; content: any[] }) => (
Expand Down Expand Up @@ -44,25 +55,124 @@ const OutputSection = (props: { title: string; content: any[] }) => (
</AccordionItem>
);

export const SolutionView = (props: SolutionViewProps) => (
<Accordion defaultIndex={[0]} width="100%" marginTop="2rem" allowMultiple>
<OutputSection
title={`Solution by ${props.solution.solverName}`}
content={[props.solution.solutionData]}
/>
<OutputSection
title="Meta Data"
content={[
`Problem ID: ${props.solution.id}`,
`Solver: ${props.solution.solverName}`,
`Execution time: ${props.solution.executionMilliseconds / 1000}s`,
`Additional meta data: ${props.solution.metaData}`,
]}
/>
<OutputSection
title="Debugging Info"
content={[props.solution.debugData]}
/>
{/*<OutputSection title="Error" content={[props.solution.error]} />*/}
</Accordion>
const DictOutputSection = (props: {
title: string;
content: [string, any][];
}) => (
<AccordionItem>
<h2>
<AccordionButton>
<Box as="span" flex="1" textAlign="left">
{props.title}
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
{props.content.map((contentChunk, chunkIndex) => {
return (
<AccordionPanel pb="4" key={chunkIndex}>
{contentChunk !== null && contentChunk !== undefined ? (
<Code width="100%" padding="1rem">
<pre style={{ overflowX: "auto" }}>
{contentChunk[0] + ": "}
{typeof contentChunk[1] === "string" ||
contentChunk[1] instanceof String ||
React.isValidElement(contentChunk[1])
? contentChunk[1]
: JSON.stringify(contentChunk, null, "\t")}
</pre>
</Code>
) : (
<i>No {props.title} output!</i>
)}
</AccordionPanel>
);
})}
</AccordionItem>
);

export const SolutionView = (props: SolutionViewProps) => {
const { updateProblem } = useGraphUpdates();
const [comparison, setComparison] = useState<number>();
const [boundError, setBoundError] = useState(false);

function getBound() {
fetchProblemBounds(props.problem.typeId, props.problem.id).then((res) => {
if (res.error) {
setBoundError(true);
} else {
updateProblem(props.problem.id);
}
});
}

function getBoundComparison() {
fetchProblemBoundComparison(props.problem.typeId, props.problem.id).then(
(res) => {
if (res) {
setComparison(Math.round(res.comparison * 10000) / 10000);
}
}
);
}

const ComparisonDisplay = () => {
if (boundError) {
return (
<Text>Error fetching bound, comparison is no longer applicable.</Text>
);
}
if (!props.problem.bound?.bound)
return <Text>Estimate a bound first!</Text>;
return (
<VariableDependentDisplay
buttonTitle={"Get Bound comparison"}
variable={comparison}
getter={() => getBoundComparison()}
/>
);
};

return (
<Accordion defaultIndex={[0]} width="100%" marginTop="2rem" allowMultiple>
<OutputSection
title={`Solution by ${props.problem.solution.solverName}`}
content={[props.problem.solution.solutionData]}
/>
<DictOutputSection
title="Meta Data"
content={[
["Solution ID", props.problem.solution.id],
["Solver", props.problem.solution.solverName],
[
"Execution time",
(props.problem.solution.executionMilliseconds / 1000).toString(),
],
[
"Bound",
boundError ? (
<Text>Error fetching bound.</Text>
) : (
<BoundDisplay
key={"boundDisplay"}
buttonTitle={"Get Bound"}
variable={props.problem.bound}
getter={() => getBound()}
/>
),
],
[
"Bound compared to solution",
<ComparisonDisplay key={"comparisonDisplay"} />,
],
["Additional meta data", props.problem.solution.metaData],
]}
/>
<OutputSection
title="Debugging Info"
content={[props.problem.solution.debugData]}
/>
{/*<OutputSection title="Error" content={[props.solution.error]} />*/}
</Accordion>
);
};
Loading