Skip to content

Commit

Permalink
feat: Add demonstrators
Browse files Browse the repository at this point in the history
  • Loading branch information
Elscrux committed Sep 6, 2024
1 parent bdf0e09 commit a333fd5
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 78 deletions.
126 changes: 126 additions & 0 deletions src/components/demonstrators/Demonstrator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
Button,
FormControl,
FormLabel,
HStack,
Spinner,
Text,
Tooltip,
VStack,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
import { getInvalidProblemDto } from "../../api/data-model/ProblemDto";
import { ProblemState } from "../../api/data-model/ProblemState";
import { SolverSetting } from "../../api/data-model/SolverSettings";
import { fetchSolverSettings, postProblem } from "../../api/ToolboxAPI";
import { settingComponentMap } from "../solvers/settings/SettingsView";

export interface DemonstratorProps {
demonstratorId: string;
onSolved: (solution: string) => void;
}

enum DemonstratorState {
IDLE,
SOLVING,
SOLVED,
}

function getHumanReadableState(state: DemonstratorState) {
switch (state) {
case DemonstratorState.IDLE:
return "Go";
case DemonstratorState.SOLVING:
return (
<HStack gap="1rem">
<Text>Running</Text>
<Spinner speed="1s" width="10px" height="10px" thickness="1px" />
</HStack>
);
case DemonstratorState.SOLVED:
return "Run again";
}
}

const demonstratorTypeId = "demonstrator";

export const Demonstrator = (props: DemonstratorProps) => {
const [settings, setSettings] = useState<SolverSetting[]>([]);
const [state, setState] = useState<DemonstratorState>(DemonstratorState.IDLE);
const [error, setError] = useState<string>("");

useEffect(() => {
fetchSolverSettings(demonstratorTypeId, props.demonstratorId).then(
setSettings
);
}, [props.demonstratorId]);

function updateSetting(newSetting: SolverSetting) {
const index = settings.findIndex(
(setting) => setting.name === newSetting.name
);
if (index !== -1) {
settings.splice(index, 1, newSetting);
}

setSettings([...settings]);
}

return (
<VStack spacing={5}>
{settings.map((setting) => {
const SettingComponent = settingComponentMap[setting.type];
return (
<FormControl
key={setting.name}
id={setting.name}
isRequired={setting.required}
>
<Tooltip label={setting.description}>
<FormLabel>{setting.name}</FormLabel>
</Tooltip>
<SettingComponent setting={setting} updateSetting={updateSetting} />
</FormControl>
);
})}

<Button
bg="kitGreen"
width="100%"
_hover={{
bg:
state === DemonstratorState.SOLVING ? "kitGreen" : "kitGreenAlpha",
}}
textColor="white"
onClick={() => {
if (state === DemonstratorState.SOLVING) return;

setState(DemonstratorState.SOLVING);
postProblem(demonstratorTypeId, {
...getInvalidProblemDto(),
input: "",
solverId: props.demonstratorId,
state: ProblemState.SOLVING,
solverSettings: settings,
}).then((problemDto) => {
setState(DemonstratorState.SOLVED);
if (problemDto.error) {
setError(problemDto.error);
props.onSolved("");
} else if (problemDto.solution?.debugData) {
setError(problemDto.solution.debugData);
props.onSolved("");
} else {
setError("");
props.onSolved(problemDto.solution.solutionData);
}
});
}}
>
{getHumanReadableState(state)}
</Button>

{error && <Text color="red">{error}</Text>}
</VStack>
);
};
65 changes: 65 additions & 0 deletions src/components/landing-page/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Badge, Box, LinkBox, LinkOverlay } from "@chakra-ui/react";
import NextLink from "next/link";

export interface CardProps {
href: string;
new?: boolean;
tags?: string[];
title: string;
description: string;
}

export const Card = (props: CardProps & { refer: string }) => {
return (
<LinkBox maxW="sm" borderWidth="1px" borderRadius="lg" overflow="hidden">
<Box p="6">
<Box display="flex" alignItems="baseline">
{props.new && (
<Badge borderRadius="full" px="2" colorScheme="blue" mr="2">
New!
</Badge>
)}
<Box
color="gray.500"
fontWeight="semibold"
letterSpacing="wide"
fontSize="xs"
textTransform="uppercase"
>
{props.tags &&
props.tags.map((tag) => (
<Badge
key={tag}
borderRadius="full"
px="2"
colorScheme="teal"
mr="2"
>
{tag}
</Badge>
))}
</Box>
</Box>

<Box
mt="2"
mb="1"
fontWeight="semibold"
as="h4"
lineHeight="tight"
noOfLines={1}
>
<NextLink href={props.href} passHref>
<LinkOverlay>{props.title}</LinkOverlay>
</NextLink>
</Box>

<Box>{props.description}</Box>

<Box fontWeight="semibold" mt="4">
{props.refer} &rarr;
</Box>
</Box>
</LinkBox>
);
};
5 changes: 5 additions & 0 deletions src/components/landing-page/DemonstratorCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Card, CardProps } from "./Card";

export const DemonstratorCard = (props: CardProps) => {
return <Card {...props} refer="Demonstrate" />;
};
15 changes: 15 additions & 0 deletions src/components/landing-page/DemonstratorChooser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Grid, GridItem, GridProps } from "@chakra-ui/react";
import { DemonstratorCard } from "./DemonstratorCard";

export const DemonstratorChooser = (props: GridProps) => (
<Grid templateColumns="repeat(2, 1fr)" gap={6} {...props}>
<GridItem>
<DemonstratorCard
new={true}
href="demonstrate/MixedIntegerProgramming"
title="Mixed Integer Programming"
description="The MIP problem is a mathematical optimization problem where some or all of the variables are restricted to be integers."
/>
</GridItem>
</Grid>
);
65 changes: 3 additions & 62 deletions src/components/landing-page/ProblemCard.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,5 @@
import { Badge, Box, LinkBox, LinkOverlay } from "@chakra-ui/react";
import NextLink from "next/link";
import { Card, CardProps } from "./Card";

interface ProblemCardProps {
href: string;
new: boolean;
tags: string[];
problemName: string;
description: string;
}

export const ProblemCard = (props: ProblemCardProps) => {
return (
<LinkBox maxW="sm" borderWidth="1px" borderRadius="lg" overflow="hidden">
<Box p="6">
<Box display="flex" alignItems="baseline">
{props.new && (
<Badge borderRadius="full" px="2" colorScheme="blue" mr="2">
New!
</Badge>
)}
<Box
color="gray.500"
fontWeight="semibold"
letterSpacing="wide"
fontSize="xs"
textTransform="uppercase"
>
{props.tags.map((tag) => (
<Badge
key={tag}
borderRadius="full"
px="2"
colorScheme="teal"
mr="2"
>
{tag}
</Badge>
))}
</Box>
</Box>

<Box
mt="2"
mb="1"
fontWeight="semibold"
as="h4"
lineHeight="tight"
noOfLines={1}
>
<NextLink href={props.href} passHref>
<LinkOverlay>{props.problemName}</LinkOverlay>
</NextLink>
</Box>

<Box>{props.description}</Box>

<Box fontWeight="semibold" mt="4">
Solve this problem &rarr;
</Box>
</Box>
</LinkBox>
);
export const ProblemCard = (props: CardProps) => {
return <Card {...props} refer="Solve this problem" />;
};
15 changes: 6 additions & 9 deletions src/components/landing-page/ProblemChooser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,24 @@ export const ProblemChooser = (props: GridProps) => (
<GridItem>
<ProblemCard
href="solve/SAT"
new={false}
tags={["simulated"]}
problemName="SAT"
title="SAT"
description="For a given Boolean formula, this algorithm checks if there exists an interpretation that satisfies it."
/>
</GridItem>
<GridItem>
<ProblemCard
href="solve/MaxCut"
new={false}
tags={["QAOA"]}
problemName="MaxCut"
title="MaxCut"
description="For a given undirected, weighted graph, this algorithm finds a cut that is a maximum in some way or another."
/>
</GridItem>
<GridItem>
<ProblemCard
href="solve/FeatureModelAnomaly"
new={false}
tags={["sub-routines", "SAT"]}
problemName="Feature Model Anomaly"
title="Feature Model Anomaly"
description="Check whether a given feature model in the UVL format is void or if it has dead features."
/>
</GridItem>
Expand All @@ -35,7 +32,7 @@ export const ProblemChooser = (props: GridProps) => (
href="solve/QUBO"
new={true}
tags={["QAOA", "Annealing"]}
problemName="QUBO"
title="QUBO"
description="For a quadratic term with binary decision variables, find the variable assignment minimizing the term."
/>
</GridItem>
Expand All @@ -44,7 +41,7 @@ export const ProblemChooser = (props: GridProps) => (
href="solve/VehicleRouting"
new={true}
tags={["sub-routines", "QUBO", "Clustering"]}
problemName="Vehicle Routing"
title="Vehicle Routing"
description="What is the optimal set of routes for a fleet of vehicles to traverse in order to deliver to a given set of customers?"
/>
</GridItem>
Expand All @@ -53,7 +50,7 @@ export const ProblemChooser = (props: GridProps) => (
href="solve/TSP"
new={true}
tags={["sub-routines", "qubo"]}
problemName="Traveling Salesperson Problem"
title="Traveling Salesperson Problem"
description="Given a list of cities and the distances between them, find the shortest possible route that visits each city exactly once and returns to the origin city."
/>
</GridItem>
Expand Down
2 changes: 1 addition & 1 deletion src/components/solvers/settings/SettingsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface Disabled {

export type OptionalSolverSetting = SolverSetting & Disabled;

const settingComponentMap: {
export const settingComponentMap: {
[key in SolverSettingType]: FC<SettingProps<any>>;
} = {
[SolverSettingType.INTEGER]: IntegerSettingView,
Expand Down
35 changes: 35 additions & 0 deletions src/pages/demonstrate/MixedIntegerProgramming.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Flex, Heading, Text } from "@chakra-ui/react";
import { NextPage } from "next";
import { useState } from "react";
import { Demonstrator } from "../../components/demonstrators/Demonstrator";
import { Layout } from "../../components/layout/Layout";

const MixedIntegerProgramming: NextPage = () => {
const [svg, setSvg] = useState<string | null>(null);

return (
<Layout>
<Heading as="h1">Mixed Integer Programming Demonstrator</Heading>
<Text color="text" align="justify">
This demonstrator will provide a visual benchmark representation of the
Mixed Integer Programming (MIP) problem based on a variable number of
variables and repetitions. The MIP problem is a mathematical
optimization problem where some or all of the variables are restricted
to be integers.
</Text>

<Demonstrator
demonstratorId="edu.kit.provideq.toolbox.demonstrators.CplexMipDemonstrator"
onSolved={setSvg}
/>

{svg && (
<Flex justifyContent="center">
<div dangerouslySetInnerHTML={{ __html: svg }} />
</Flex>
)}
</Layout>
);
};

export default MixedIntegerProgramming;
Loading

0 comments on commit a333fd5

Please sign in to comment.