Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/frontend/vue/components/MiniComposer/CircuitSandboxWidget.vue
3376 views
<template>
  <section class="mini-composer">
    <div
      ref="configRef"
      class="mini-composer__config-container"
    >
      <slot />
    </div>
    <div
      ref="instructionsRef"
      class="mini-composer__exercise-text"
    />
    <div class="mini-composer__gates">
      <h1 class="mini-composer__gates__title">
        Gates
      </h1>
      <GatesPool :available-gates="availableGates" />
    </div>
    <div class="mini-composer__circuit-section">
      <h1 class="mini-composer__circuit-section__title">
        Circuit
      </h1>
      <button
        class="mini-composer__circuit-section__reset"
        @click="onResetButton"
      >
        Reset <ResetIcon class="mini-composer__circuit-section__reset__icon" />
      </button>
      <Circuit
        class="mini-composer__circuit-section__circuit-lines"
        :circuit-state="circuitState"
        :auto-measure-gate="false"
        :max-lines="circuitState.length"
        :max-gates="MAX_GATES"
      />
    </div>
    <div
      ref="explanationRef"
      class="mini-composer__explanation"
    />
    <div class="mini-composer__state-views">
      <section>
        <h1 class="mini-composer__state-views__title">
          Matrix
        </h1>
        <SymbolicNotation
          class="mini-composer__state-views__area"
          :tex="matrixTex"
        />
      </section>
      <section>
        <h1 class="mini-composer__state-views__title">
          State Vector
        </h1>
        <SymbolicNotation
          class="mini-composer__state-views__area"
          :tex="stateVectorTex"
        />
      </section>
    </div>
  </section>
</template>

<script lang="ts">
import { ref } from '@vue/reactivity'
import { Options, Vue, prop } from 'vue-class-component'
import draggable from 'vuedraggable'
import ResetIcon from '@carbon/icons-vue/lib/reset/16'
import SolutionStateIndicator from '../common/SolutionStateIndicator.vue'
import GatesPool from './GatesPool.vue'
import Circuit from './Circuit.vue'
import { ComposerGate, gateMatrix } from './composerTypes'
import { GateName, IdentityState, StateMatrixToTexMatrix, StateMatrixToTexKetNotation } from './gateUtils'
import SymbolicNotation from './SymbolicNotation.vue'

class Props {
  goal = prop<String>({ default: 'mini-composer-solved', required: true })
}

@Options({
  components: {
    Circuit,
    GatesPool,
    draggable,
    SymbolicNotation,
    SolutionStateIndicator,
    ResetIcon
  }
})
export default class CircuitSandboxWidget extends Vue.with(Props) {
  configRef = ref<HTMLDivElement | null>(null)
  get configDiv () { return (this.configRef as unknown as HTMLDivElement) }
  instructionsRef = ref<HTMLDivElement | null>(null)
  get instructions () { return (this.instructionsRef as unknown as HTMLDivElement) }
  explanationRef = ref<HTMLDivElement | null>(null)
  get explanation () { return (this.explanationRef as unknown as HTMLDivElement) }

  MAX_GATES = 7

  initialAvailableGates: ComposerGate[] = []
  get availableGates (): ComposerGate[] {
    return this.initialAvailableGates.map(gate => gate)
  }

  circuitState: ComposerGate[][] = [[]]

  get matrixState () {
    if (this.goal && this.circuitState[0].length > 0) {
      this.$step?.score(this.goal as string)
    }

    return this.circuitState[0].reduce((prev, current) => {
      return gateMatrix(current).apply(prev)
    }, IdentityState())
  }

  get matrixTex () {
    return StateMatrixToTexMatrix(this.matrixState)
  }

  get stateVectorTex () {
    return StateMatrixToTexKetNotation(this.matrixState)
  }

  mounted () {
    const instructionElement = this.configDiv.querySelector('.instructions')
    const explanationElement = this.configDiv.querySelector('.explanation')
    const availableGatesElement = this.configDiv.querySelector('.availableGates')

    this.setCircuitConfig(availableGatesElement as HTMLElement)

    if (instructionElement) {
      this.instructions.appendChild(instructionElement)
    } else {
      this.instructions.remove()
    }
    if (explanationElement) {
      this.explanation.appendChild(explanationElement)
    } else {
      this.explanation.remove()
    }
  }

  setCircuitConfig (availableGatesElement: HTMLElement) {
    this.initialAvailableGates = []
    if (availableGatesElement && availableGatesElement.textContent) {
      this.initialAvailableGates = this.stringToGateNameArray(availableGatesElement.textContent)
    }
  }

  stringToGateNameArray (text: string) : ComposerGate[] {
    let lastGateId = 0
    return text.split(' ')
      .filter(text => text !== '')
      .map<ComposerGate>((gateText: string) => {
        if (Object.values(GateName).some(gate => gateText.startsWith(gate))) {
          const parts = gateText.split('(')
          const gateName = parts[0]
          const rotation = parts[1]?.split(')')[0]
          return { name: gateName as GateName, id: lastGateId++, rotation }
        }
        return { name: GateName.UNKNOWN, id: lastGateId++ }
      })
  }

  onResetButton () {
    this.circuitState = [[]]
  }
}
</script>
<style scoped lang="scss">
@import 'carbon-components/scss/globals/scss/typography';
@import 'carbon-components/scss/globals/scss/layout';
@import '../../../scss/variables/colors.scss';
@import '~/../scss/variables/mq.scss';

.mini-composer {
  display: grid;
  grid-template-columns: 20rem 1fr;
  grid-template-rows: min-content min-content 1fr min-content;
  grid-template-areas:
    "text text"
    "gates lesson"
    "circuit lesson"
    "explanation lesson";

  @include mq ($until: medium) {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(5, min-content);
    grid-template-areas:
      "text"
      "gates"
      "circuit"
      "explanation"
      "lesson";
  }

  &__config-container {
    display: none;
  }

  &__exercise-text {
    @include type-style('body-long-01');
    grid-area: text;
    border-bottom: 1px solid $border-color;
    padding: $spacing-05;
  }
  &__explanation {
    @include type-style('body-long-01');
    grid-area: explanation;
    padding: $spacing-05;
  }
  &__gates {
    grid-area: gates;
    border-bottom: 1px solid $border-color;
    padding: $spacing-05;
    &__title {
      margin: $spacing-03 0 $spacing-05 0;
      @include type-style('heading-01');
    }
  }
  &__circuit-section {
    grid-area: circuit;
    padding: $spacing-05;
    display: grid;
    grid-template-columns: 1fr 4rem;
    grid-template-rows: min-content 1fr;
    grid-template-areas:
      "title reset"
      "line line";

    &__title {
      grid-area: title;
      margin-top: $spacing-03;
      @include type-style('heading-01');
    }
    &__reset {
      @include type-style('body-short-01');
      grid-area: reset;
      display: flex;
      flex-flow: row;
      gap: $spacing-03;
      color: $link-color-tertiary;
      align-items: center;
      &__icon{
        height: 1rem;
      }
      &:hover {
        color: $link-hover-color-tertiary;
      }
    }
    &__circuit-lines {
      grid-area: line;
    }
  }
  &__state-views {
    grid-area: lesson;
    display: flex;
    flex-direction: column;
    gap: $spacing-05;
    border-left: 1px solid $border-color;
    padding: $spacing-05;

    @include mq ($until: medium) {
      border-left: none;
      border-top: 1px solid $border-color;
    }

    &__title {
      @include type-style('heading-01');
      margin-top: $spacing-03;
    }
    &__area {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;

      height: 9rem;
      width: 100%;
      border: 2px solid $border-color;
      background-color: $background-color-white;
    }
  }
}
</style>