All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cyc.query.explanations.ProofViewGeneratorImpl Maven / Gradle / Ivy

Go to download

Query API implementation for requesting and handling answers to arbitrarily complex questions posed to a Cyc server.

There is a newer version: 1.2.2
Show newest version
package com.cyc.query.explanations;

/*
 * #%L
 * File: ProofViewGeneratorImpl.java
 * Project: Query Client
 * %%
 * Copyright (C) 2013 - 2017 Cycorp, Inc.
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
import com.cyc.base.CycAccess;
import com.cyc.base.CycAccessSession;
import com.cyc.base.cycobject.CycObject;
import com.cyc.base.cycobject.CycSymbol;
import com.cyc.base.cycobject.DenotationalTerm;
import com.cyc.base.exception.CycApiException;
import com.cyc.base.exception.CycConnectionException;
import com.cyc.baseclient.CycObjectFactory;
import static com.cyc.baseclient.CycObjectFactory.makeCycSymbol;
import com.cyc.baseclient.connection.SublApiHelper;
import static com.cyc.baseclient.connection.SublApiHelper.makeNestedSubLStmt;
import static com.cyc.baseclient.connection.SublApiHelper.makeSubLStmt;
import com.cyc.kb.Context;
import com.cyc.kb.ContextFactory;
import com.cyc.kb.exception.CreateException;
import com.cyc.kb.exception.KbTypeException;
import com.cyc.query.InferenceAnswerIdentifier;
import com.cyc.query.InferenceIdentifier;
import com.cyc.query.ProofViewGenerator;
import com.cyc.query.ProofViewSpecification;
import com.cyc.query.QueryAnswer;
import com.cyc.query.QueryAnswerExplanationGenerator;
import com.cyc.query.exception.QueryRuntimeException;
import com.cyc.session.compatibility.CycSessionRequirementList;
import com.cyc.session.compatibility.NotOpenCycRequirement;
import com.cyc.session.exception.OpenCycUnsupportedFeatureException;
import com.cyc.session.exception.SessionCommunicationException;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import javax.xml.bind.JAXBException;

/**
 * A {@link QueryAnswerExplanationGenerator} backed by a {@link ProofView}.
 *
 * Generally, a new ProofViewGenerator object is constructed, parameters are set as desired, then
 * {@link #generate()} is called to flesh it out. Then you can get its root note (via
 * {@link #getExplanation()}), and display it as an interactive tree structure.
 *
 * @author baxter
 */
public class ProofViewGeneratorImpl implements ProofViewGenerator {

  private final ProofViewSpecification spec;
  private final CycAccess cyc;
  private QueryAnswer answer;
  private final int proofViewId;
  private boolean isPopulated = false;

  final private Object lock = new Object();
  private SummaryAlgorithm summaryAlgorithm = SummaryAlgorithm.DEFAULT;
  private DenotationalTerm addressee = null;
  private com.cyc.xml.query.ProofView proofViewJaxb = null;
  private final com.cyc.xml.query.ProofViewUnmarshaller proofViewJaxbUnmarshaller;
  private com.cyc.query.ProofView root = null;
  //"get-new-empty-proof-view-id"

  public static final CycSessionRequirementList PROOF_VIEW_JUSTIFICATION_REQUIREMENTS = CycSessionRequirementList.fromList(
          NotOpenCycRequirement.NOT_OPENCYC
  );

  /**
   * Create a new, unpopulated justification for the specified answer.
   *
   * @param answer
   * @param spec
   * @throws CycConnectionException if there is a problem talking to Cyc.
   * @throws OpenCycUnsupportedFeatureException when run against an OpenCyc server.
   * @see ProofViewJustification#populate()
   */
  public ProofViewGeneratorImpl(QueryAnswer answer, ProofViewSpecification spec) throws CycConnectionException, OpenCycUnsupportedFeatureException {
    PROOF_VIEW_JUSTIFICATION_REQUIREMENTS.throwRuntimeExceptionIfIncompatible();
    this.answer = answer;
    this.spec = spec;
    final InferenceAnswerIdentifier answerID = answer.getId();
    final InferenceIdentifier inferenceID = answerID.getInferenceIdentifier();
    try {
      this.cyc = ((CycAccessSession) (inferenceID.getSession())).getAccess();
      this.proofViewId = cyc.converse().converseInt(makeSubLStmt(
              "get-new-empty-proof-view-id",
              inferenceID.getProblemStoreId(), inferenceID.getInferenceId(),
              answerID.getAnswerId()));
      this.proofViewJaxbUnmarshaller = new com.cyc.xml.query.ProofViewUnmarshaller();
    } catch (JAXBException ex) {
      throw new RuntimeException(ex);
    } catch (CycConnectionException ex) {
      throw new QueryRuntimeException(ex);
    }
  }


  public ProofViewGeneratorImpl(QueryAnswer answer) throws CycConnectionException, OpenCycUnsupportedFeatureException {
    this(answer, new ProofViewSpecificationImpl());
  }
  
  @Deprecated
  @Override
  public QueryAnswer getAnswer() {
    throw new UnsupportedOperationException("Use getQueryAnswer() instead.");
  }

  public QueryAnswer getQueryAnswer() {
    return answer;
  }

  /**
   * Flesh out this justification, setting its root node and tree structure underneath the root.
   *
   * @throws com.cyc.session.exception.OpenCycUnsupportedFeatureException when run against an
   * OpenCyc server.
   */
  @Override
  public void generate() throws OpenCycUnsupportedFeatureException {
    synchronized (lock) {
      PROOF_VIEW_JUSTIFICATION_REQUIREMENTS.throwRuntimeExceptionIfIncompatible();
      requireNotPopulated();
      try {
        initializeProofViewProperties();
        converseVoid(makeSubLStmt("proof-view-id-populate", proofViewId));
      } catch (Exception e) {
        throw new RuntimeException("Failed to populate proof view.", e);
      }
      isPopulated = true;
    }
  }

  public void initializeProofViewProperties() {
    if (spec == null) {
      return;
    }
    try {
      ArrayList propertySetters = new ArrayList<>();
      if (spec.isIncludeDetails() instanceof Boolean) {
        propertySetters.add(makeNestedSubLStmt("set-proof-view-include-details",
                proofViewId,
                spec.isIncludeDetails()));
      }
      if (spec.isIncludeLinear() instanceof Boolean) {
        propertySetters.add(makeNestedSubLStmt("set-proof-view-include-linear", proofViewId,
                spec.isIncludeLinear()));
      }
      if (spec.isIncludeSummary() instanceof Boolean) {
        propertySetters.add(makeNestedSubLStmt("set-proof-view-include-summary", proofViewId, spec.isIncludeSummary()));
      }
      if (spec.getDomainContext() instanceof Context) {
        propertySetters.add(makeNestedSubLStmt("set-proof-view-domain-mt", proofViewId, spec.getDomainContext().getCore()));
      }
      if (spec.getLanguageContext() instanceof Context) {
        propertySetters.add(makeNestedSubLStmt("set-proof-view-language-mt", proofViewId, spec.getLanguageContext().getCore()));
      }
      if (spec.isIncludeAssertionBookkeeping() instanceof Boolean) {
        propertySetters.add(makeNestedSubLStmt("set-proof-view-suppress-assertion-bookkeeping", proofViewId,!spec.isIncludeAssertionBookkeeping()));
      }
      if (spec.isIncludeAssertionCyclists() instanceof Boolean) {
        propertySetters.add(makeNestedSubLStmt("set-proof-view-suppress-assertion-cyclists", proofViewId,!spec.isIncludeAssertionCyclists()));
      }
      String command = makeSubLStmt("progn", propertySetters.toArray());
      getCyc().converse().converseVoid(command);
      
    } catch (CycConnectionException ex) {
      throw new QueryRuntimeException(ex);
    }
  }
  
  @Override
  public String toString() {
    return "Proof View for " + answer;
  }

  /**
   * Get the microtheory from which semantic checks are performed to construct this justification.
   *
   * @return the domain microtheory
   * @throws com.cyc.session.exception.SessionCommunicationException
   * @see #setDomainMt(ELMt)
   */
  public Context getDomainContext() throws SessionCommunicationException {
    if (spec.getDomainContext() == null) {
      try {
        final CycObject mtObject = cyc.converse().converseCycObject(makeSubLStmt(
                "get-proof-view-domain-mt", proofViewId));
        return ContextFactory.get(mtObject.toString());
      } catch (CycConnectionException ex) {
        throw new SessionCommunicationException(ex);
      } catch (CreateException | KbTypeException ex) {
        throw new QueryRuntimeException(ex);
      }
    }
    return spec.getDomainContext();
  }

  /**
   * Should we include a detailed, drill-down section in this justification?
   *
   * @return true iff such a tree is or should be included
   * @throws com.cyc.session.exception.SessionCommunicationException
   * @see #setIncludeDetails(boolean)
   */
  public boolean isIncludeDetails() throws SessionCommunicationException {
    if (spec.isIncludeDetails() == null) {
      try {
        return cyc.converse().converseBoolean(makeSubLStmt(
                "get-proof-view-include-details", proofViewId));
      } catch (CycConnectionException ex) {
        throw new SessionCommunicationException(ex);
      }
    } else {
      return spec.isIncludeDetails();
    }
  }

  /**
   * Should we include a linear, syllogistic section in this justification?
   *
   * @return true iff such a section is or should be included
   * @throws com.cyc.session.exception.SessionCommunicationException
   * @see #setIncludeLinear(boolean)
   */
  public boolean isIncludeLinear() throws SessionCommunicationException {
    if (spec.isIncludeLinear() == null) {
      try {
        return cyc.converse().converseBoolean(makeSubLStmt(
                "get-proof-view-include-linear", proofViewId));
      } catch (CycConnectionException ex) {
        throw new SessionCommunicationException(ex);
      }
    } else {
      return spec.isIncludeLinear();
    }
  }

  /**
   * Should we include a short, executive-summary section in this justification?
   *
   * @return true iff such a section is or should be included
   * @throws com.cyc.session.exception.SessionCommunicationException
   * @see #setIncludeSummary(boolean)
   */

  public boolean isIncludeSummary() throws SessionCommunicationException {
    if (spec.isIncludeSummary() == null) {
      try {
        final String command = makeSubLStmt(
                "get-proof-view-include-summary", proofViewId);
        return cyc.converse().converseBoolean(command);
      } catch (CycConnectionException ex) {
        throw new SessionCommunicationException(ex);
      }
    } else {
      return spec.isIncludeSummary();
    }
  }

  /**
   * Returns the microtheory used for natural-language generation in this justification
   *
   * @return the language microtheory
   * @throws com.cyc.session.exception.SessionCommunicationException
   * @throws com.cyc.kb.exception.KbTypeException
   * @throws com.cyc.kb.exception.CreateException
   * @see #setLanguageMt(com.cyc.base.cycobject.ELMt)
   */
  public Context getLanguageContext() throws SessionCommunicationException, KbTypeException, CreateException {
    if (spec.getLanguageContext() == null) {
      try {
        final CycObject mtObject = cyc.converse().converseCycObject(makeSubLStmt(
                "get-proof-view-language-mt", proofViewId));
        return ContextFactory.get(mtObject.toString());
      } catch (CycConnectionException ex) {
        throw new SessionCommunicationException(ex);
      }
    }
    return spec.getLanguageContext();
  }

  CycAccess getCyc() {
    return cyc;
  }

  com.cyc.xml.query.ProofViewUnmarshaller getProofViewJaxbUnmarshaller() {
    return proofViewJaxbUnmarshaller;
  }

  /**
   * Get the JAXB-generated proof view object backing this justification.
   *
   * @return the proof view.
   * @throws com.cyc.session.exception.OpenCycUnsupportedFeatureException when run against an
   * OpenCyc server.
   */
  public com.cyc.xml.query.ProofView getProofViewJaxb() throws OpenCycUnsupportedFeatureException {
    ensureProofViewInitialized();
    return proofViewJaxb;
  }

  /**
   * Get the root of the tree structure of this justification. A suggested rendering algorithm would
   * display this node, and recurse on its child nodes iff it is to be expanded initially.
   *
   * @see com.cyc.base.justification.Justification.Node#isExpandInitially()
   * @return the root node
   */
  @Override
  public com.cyc.query.ProofView getExplanation() throws OpenCycUnsupportedFeatureException {
    ensureProofViewInitialized();
    return root;
  }

  String requireNamespace(String command) {
    return SublApiHelper.wrapVariableBinding(
            command, makeCycSymbol("*proof-view-include-namespace?*"),
            makeCycSymbol("T"));
  }

  private void setRoot(com.cyc.query.ProofView root) {
    this.root = root;
  }

  /**
   * Should bookkeeping data for assertions be included? . Bookkeeping data includes who made the
   * assertion and when, etc.
   *
   * @return true iff it should
   * @throws com.cyc.session.exception.SessionCommunicationException
   * @see #setSuppressAssertionBookkeeping(boolean)
   */
  public boolean isIncludeAssertionBookkeeping() throws SessionCommunicationException {
    if (spec.isIncludeAssertionBookkeeping() != null) {
      return spec.isIncludeAssertionBookkeeping();
    }
    try {
      return ! cyc.converse().converseBoolean(makeSubLStmt(
              "get-proof-view-suppress-assertion-bookkeeping", proofViewId));
    } catch (CycConnectionException ex) {
      throw new SessionCommunicationException(ex);
    }
  }

  /**
   * Should the cyclist who made a given assertion be cited?
   *
   * @return true iff the cyclist should be cited
   * @throws com.cyc.session.exception.SessionCommunicationException
   * @see #setSuppressAssertionCyclists(boolean)
   */
  public boolean isIncludeAssertionCyclists() throws SessionCommunicationException {
    if (spec.isIncludeAssertionCyclists() != null) {
      return spec.isIncludeAssertionCyclists();
    }
    try {
      return ! cyc.converse().converseBoolean(makeSubLStmt(
              "get-proof-view-suppress-assertion-cyclists", proofViewId));
    } catch (CycConnectionException ex) {
      throw new SessionCommunicationException(ex);
    }
  }

  public SummaryAlgorithm getSummaryAlgorithm() {
    return summaryAlgorithm;
  }

  public void setSummaryAlgorithm(final SummaryAlgorithm algorithm) throws SessionCommunicationException {
    synchronized (lock) {
      try {
        requireNotPopulated();
        converseVoid(makeSubLStmt("set-proof-view-summary-algorithm",
                proofViewId, algorithm.getCycName()));
        this.summaryAlgorithm = algorithm;
      } catch (CycConnectionException ex) {
        throw new SessionCommunicationException(ex);
      }
    }
  }

  public DenotationalTerm getAddressee() {
    return addressee;
  }

  public void setAddressee(final DenotationalTerm addressee) throws SessionCommunicationException {
    synchronized (lock) {
      try {
        requireNotPopulated();
        converseVoid(makeSubLStmt("set-proof-view-addressee",
                proofViewId, addressee));
        this.addressee = addressee;
      } catch (CycConnectionException ex) {
        throw new SessionCommunicationException(ex);

      }
    }
  }

  public enum SummaryAlgorithm {

    DEFAULT(":default"), WHITELIST(":whitelist");
    private final CycSymbol cycName;

    private SummaryAlgorithm(final String cycName) {
      this.cycName = CycObjectFactory.makeCycSymbol(cycName);
    }

    private CycSymbol getCycName() {
      return cycName;
    }
  }

  @Override
  public void marshal(org.w3c.dom.Node destination) {
    try {
      marshal(destination, new com.cyc.xml.query.ProofViewMarshaller());
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  /**
   * Marshal this justification to the specified DOM node using the specified marshaller.
   *
   * @param destination
   * @param marshaller
   */
  public void marshal(org.w3c.dom.Node destination,
          final com.cyc.xml.query.ProofViewMarshaller marshaller) {
    try {
      marshaller.marshal(proofViewJaxb, destination);
    } catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  private void requireNotPopulated() throws UnsupportedOperationException {
    if (isPopulated) {
      throw new UnsupportedOperationException(
              "Justification already populated.");
    }
  }

  private void converseVoid(final String command) throws CycConnectionException {
    try {
      cyc.converse().converseVoid(command);
    } catch (CycApiException e) {
      throw new QueryRuntimeException(e);
    }
  }

  private boolean converseBoolean(final String command) throws CycConnectionException {
    try {
      return cyc.converse().converseBoolean(command);
    } catch (CycApiException e) {
      throw new QueryRuntimeException(e);
    }
  }

  private CycObject converseCycObject(final String command) throws CycConnectionException {
    try {
      return cyc.converse().converseCycObject(command);
    } catch (CycApiException e) {
      throw new QueryRuntimeException(e);
    }
  }

  private void ensureProofViewInitialized() throws RuntimeException, OpenCycUnsupportedFeatureException {
    PROOF_VIEW_JUSTIFICATION_REQUIREMENTS.throwRuntimeExceptionIfIncompatible();
    synchronized (lock) {
      if (!isPopulated) {
        generate();
      }
      try {
        final String xml = cyc.converse().converseString(requireNamespace(makeSubLStmt(
                "proof-view-xml", proofViewId)));
        proofViewJaxb = (com.cyc.xml.query.ProofView) proofViewJaxbUnmarshaller.unmarshalProofview(new ByteArrayInputStream(
                xml.getBytes()));
        final com.cyc.xml.query.ProofViewEntry rootEntryJaxb = proofViewJaxb.getProofViewEntry();
        setRoot(new com.cyc.query.explanations.ProofViewImpl(rootEntryJaxb, this));
      } catch (Exception e) {
        e.printStackTrace(System.err);
        throw new QueryRuntimeException("Failed to get root of proof view.", e);
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy