Difference between revisions of "New Tactic Providers"

From Event-B
Jump to navigationJump to search
imported>Nicolas
m (Added explanations and example)
imported>Nicolas
m (→‎Example: Added category Developer documentation)
 
(17 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
The purpose is to give more flexibility to tactic providers by allowing them to provide as many tactic applications as they will for a given proof node, even they apply to the same predicate and at the same position.  
 
The purpose is to give more flexibility to tactic providers by allowing them to provide as many tactic applications as they will for a given proof node, even they apply to the same predicate and at the same position.  
  
== Proposed Framework ==
+
== A new API ==
  
The current proposal consists in the following published interfaces:
+
The new API consists in the following published interfaces:
  
 
  public interface ITacticProvider2 {
 
  public interface ITacticProvider2 {
     List<ITacticApplication> getPossibleApplications(IUserSupport userSupport,
+
     List<ITacticApplication> getPossibleApplications(IProofTreeNode node,
                                                    IProofTreeNode node,
 
 
                                                     Predicate hyp,
 
                                                     Predicate hyp,
 
                                                     String globalInput);
 
                                                     String globalInput);
Line 13: Line 12:
  
 
  public interface ITacticApplication {
 
  public interface ITacticApplication {
     void apply(String[] inputs,
+
     ITactic getTactic(String[] inputs,
               String globalInput,
+
               String globalInput);
              IProgressMonitor monitor);
+
    String getTacticID();
 
  }
 
  }
  
 
  public interface IPositionApplication  extends ITacticApplication {
 
  public interface IPositionApplication  extends ITacticApplication {
     Point getHyperlinkBounds();
+
     Point getHyperlinkBounds(String parsedString, Predicate parsedPredicate);
 
     String getHyperlinkLabel();
 
     String getHyperlinkLabel();
 
  }
 
  }
Line 28: Line 27:
 
  }
 
  }
  
The current extension point "proofTactics" remains unchanged.
+
The existing extension point "proofTactics" is added an optional attribute to allow skipping post tactic application (default is false).
  
 
All those interfaces are intended to be implemented by clients.
 
All those interfaces are intended to be implemented by clients.
  
== Explanations ==
+
=== Explanations ===
  
 
The idea is to encapsulate in {{class|ITacticApplication}} all data needed by the UI to display and apply tactics.
 
The idea is to encapsulate in {{class|ITacticApplication}} all data needed by the UI to display and apply tactics.
Thus, tactic providers, instead of returning just one fixed tactic to apply, can return several possible 'autonomous' applications.
+
Thus, an {{class|ITacticProvider2}}, instead of returning just one fixed tactic to apply, can return several possible 'autonomous' tactic applications.
 +
 
 +
 
 +
Interfaces {{class|IPositionApplication}} and {{class|IPredicateApplication}} are particular application types:
 +
 
 +
* {{class|IPositionApplication}} is for tactics applied at a given position in a formula (red hyperlinks in interactive prover UI). The {{method|getHyperlinkLabel()}} method allows to override extension point behaviour (using the fixed 'tooltip' attribute), in order to have a different text for each application in the hyperlink list. If '''null''' is returned, then default 'tooltip' from extension point is taken.
 +
 
 +
* {{class|IPredicateApplication}} is for tactics applied to a whole predicate, like 'Contradict Goal' or 'Contradict Hyp' (icons on the left of a predicate in interactive prover UI). The methods allow to override extension point behaviour (using the 'icon' and 'tooltip' attributes), in order to have a different icon and tooltip for each application in the left icon list. If '''null''' is returned, then default data from extension point is taken.
 +
 
 +
 
 +
== A different Protocol ==
 +
 
 +
The current protocol concerning the return value of tactic providers is the following:
 +
* '''null''' if not applicable
 +
* empty list of positions if applicable to predicate
 +
* non empty list of positions if applicable to a position in predicate
 +
 
 +
 
 +
The new protocol using {{class|ITacticApplication}} is the following:
 +
* an empty list of applications if not applicable
 +
* a non empty list of applications if applicable and, for each application:
 +
** an instanceof {{class|IPredicateApplication}} if applicable to predicate, even if default icon and tooltip from extension point should be used (methods returning '''null''')
 +
** an instanceof {{class|IPositionApplication}} if applicable to a position in predicate
 +
 
 +
 
 +
Thus, the distinction between application to predicate or position is based on objects's actual type. Hence, one of {{class|IPredicateApplication}} or {{class|IPositionApplication}} interface should be implemented. Only implementing {{class|ITacticApplication}} would make the UI ignore the extension.
  
 
== Example ==
 
== Example ==
 +
 +
The following example demonstrates (part of) the implementation of a tactic using the new API.
 +
For simplicity, a simple {{class|ITacticApplication}} is used, but a {{class|IPositionApplication}} should be used instead.
 +
The underlying {{class|IReasoner}} ({{class|ExampleReasoner}}) is not shown here, as it is not impacted by the new API.
  
 
<pre>
 
<pre>
// rewrites occurrences of literal 4 into either 2+2 or 2*2  
+
//rewrites occurrences of literal 4 into either 2+2 or 2*2  
 
public class ExampleTacticProvider2 implements ITacticProvider2 {
 
public class ExampleTacticProvider2 implements ITacticProvider2 {
  
 +
    // our own implementation of a tactic application
 
     private static class ExampleApplication implements ITacticApplication {
 
     private static class ExampleApplication implements ITacticApplication {
  
         private final IUserSupport userSupport;
+
         private static final String TACTIC_ID = "fr.systerel.example";
 +
   
 
         private final Predicate hyp;
 
         private final Predicate hyp;
 
         private final IPosition position;
 
         private final IPosition position;
Line 51: Line 81:
 
         private final ExampleReasoner.Kind kind;
 
         private final ExampleReasoner.Kind kind;
  
         public ExampleApplication(IUserSupport userSupport, Predicate hyp, IPosition position, Kind kind) {
+
         public ExampleApplication(Predicate hyp, IPosition position, Kind kind) {
            this.userSupport = userSupport;
 
 
             this.hyp = hyp;
 
             this.hyp = hyp;
 
             this.position = position;
 
             this.position = position;
Line 58: Line 87:
 
         }
 
         }
  
         public void apply(String[] inputs, String globalInput, IProgressMonitor monitor) {
+
         public ITactic getTactic(String[] inputs, String globalInput) {
             try {
+
             // ExampleReasoner implements IReasoner and rewrites literal 4
                // ExampleReasoner implements IReasoner and rewrites literal 4
+
            // at given position into:
                // at given position into:
+
            // . 2+2 if input.kind is PLUS
                // . 2+2 if input.kind is PLUS
+
            // . 2*2 if input.kind is MULT
                // . 2*2 if input.kind is MULT
+
            return BasicTactics.reasonerTac(
                userSupport.applyTactic(BasicTactics.reasonerTac(
+
                    new ExampleReasoner(),
                        new ExampleReasoner(),
+
                    new ExampleReasoner.Input(hyp, position, kind));
                        new ExampleReasoner.Input(hyp, position, kind)),
+
        }
                        true, monitor);
+
 
            } catch (RodinDBException e) {
+
        public String getTacticID() {
                // log the problem
+
             return TACTIC_ID;
             }
 
 
         }
 
         }
 
     }
 
     }
  
 +
    // visits a formula and adds applications on occurrences of literal 4
 
     private static class ExampleApplicationVisitor extends DefaultVisitor {
 
     private static class ExampleApplicationVisitor extends DefaultVisitor {
  
        private final IUserSupport userSupport;
 
 
         private final Predicate hyp;
 
         private final Predicate hyp;
 
         private final Predicate predicate;
 
         private final Predicate predicate;
 
         // a list to put applications into
 
         // a list to put applications into
         private final List<ITacticApplication> applications;
+
         private final List<ITacticApplication> applications =
 +
                new ArrayList<ITacticApplication>();
  
         public ExampleApplicationVisitor(IUserSupport userSupport,
+
         public ExampleApplicationVisitor(Predicate predicate, Predicate hyp) {
                Predicate predicate, Predicate hyp,
 
                List<ITacticApplication> applications) {
 
            this.userSupport = userSupport;
 
 
             this.predicate = predicate;
 
             this.predicate = predicate;
 
             this.hyp = hyp;
 
             this.hyp = hyp;
             this.applications = applications;
+
        }
 +
 
 +
        public List<ITacticApplication> getApplications() {
 +
             return applications;
 
         }
 
         }
  
Line 95: Line 124:
 
             if (lit.getValue().intValue() == 4) {
 
             if (lit.getValue().intValue() == 4) {
 
                 final IPosition position = predicate.getPosition(lit.getSourceLocation());
 
                 final IPosition position = predicate.getPosition(lit.getSourceLocation());
                 applications.add(new ExampleApplication(userSupport, hyp, position, Kind.MULT));
+
                 applications.add(new ExampleApplication(hyp, position, Kind.MULT));
                 applications.add(new ExampleApplication(userSupport, hyp, position, Kind.PLUS));
+
                 applications.add(new ExampleApplication(hyp, position, Kind.PLUS));
 
             }
 
             }
 
             return true;
 
             return true;
Line 102: Line 131:
 
     }
 
     }
  
     // the ITacticProvider2 interface method
+
     // the ITacticProvider2 interface method: calls the visitor on the predicate
     public List<ITacticApplication> getPossibleApplications(IUserSupport userSupport,
+
     public List<ITacticApplication> getPossibleApplications(IProofTreeNode node,
                                                            IProofTreeNode node,
 
 
                                                             Predicate hyp,
 
                                                             Predicate hyp,
 
                                                             String globalInput) {
 
                                                             String globalInput) {
Line 110: Line 138:
 
         final Predicate pred = (hyp == null) ? node.getSequent().goal() : hyp;
 
         final Predicate pred = (hyp == null) ? node.getSequent().goal() : hyp;
  
         final List<ITacticApplication> applications = new ArrayList<ITacticApplication>();
+
         ExampleApplicationVisitor visitor =
       
+
                new ExampleApplicationVisitor(pred, hyp);  
         pred.accept(new ExampleApplicationVisitor(userSupport, pred, hyp, applications));
+
         pred.accept(visitor);
       
+
         return visitor.getApplications();
         return applications;
 
 
     }
 
     }
}
+
}</pre>
</pre>
+
 
 +
 
 +
[[Category:Developer documentation]]

Latest revision as of 13:00, 12 October 2009

The purpose is to give more flexibility to tactic providers by allowing them to provide as many tactic applications as they will for a given proof node, even they apply to the same predicate and at the same position.

A new API

The new API consists in the following published interfaces:

public interface ITacticProvider2 {
   List<ITacticApplication> getPossibleApplications(IProofTreeNode node,
                                                    Predicate hyp,
                                                    String globalInput);
}
public interface ITacticApplication {
   ITactic getTactic(String[] inputs,
              String globalInput);
   String getTacticID();
}
public interface IPositionApplication  extends ITacticApplication {
   Point getHyperlinkBounds(String parsedString, Predicate parsedPredicate);
   String getHyperlinkLabel();
}
public interface IPredicateApplication extends ITacticApplication {
   Image getIcon();
   String getTooltip();
}

The existing extension point "proofTactics" is added an optional attribute to allow skipping post tactic application (default is false).

All those interfaces are intended to be implemented by clients.

Explanations

The idea is to encapsulate in ITacticApplication all data needed by the UI to display and apply tactics. Thus, an ITacticProvider2, instead of returning just one fixed tactic to apply, can return several possible 'autonomous' tactic applications.


Interfaces IPositionApplication and IPredicateApplication are particular application types:

  • IPositionApplication is for tactics applied at a given position in a formula (red hyperlinks in interactive prover UI). The getHyperlinkLabel() method allows to override extension point behaviour (using the fixed 'tooltip' attribute), in order to have a different text for each application in the hyperlink list. If null is returned, then default 'tooltip' from extension point is taken.
  • IPredicateApplication is for tactics applied to a whole predicate, like 'Contradict Goal' or 'Contradict Hyp' (icons on the left of a predicate in interactive prover UI). The methods allow to override extension point behaviour (using the 'icon' and 'tooltip' attributes), in order to have a different icon and tooltip for each application in the left icon list. If null is returned, then default data from extension point is taken.


A different Protocol

The current protocol concerning the return value of tactic providers is the following:

  • null if not applicable
  • empty list of positions if applicable to predicate
  • non empty list of positions if applicable to a position in predicate


The new protocol using ITacticApplication is the following:

  • an empty list of applications if not applicable
  • a non empty list of applications if applicable and, for each application:
    • an instanceof IPredicateApplication if applicable to predicate, even if default icon and tooltip from extension point should be used (methods returning null)
    • an instanceof IPositionApplication if applicable to a position in predicate


Thus, the distinction between application to predicate or position is based on objects's actual type. Hence, one of IPredicateApplication or IPositionApplication interface should be implemented. Only implementing ITacticApplication would make the UI ignore the extension.

Example

The following example demonstrates (part of) the implementation of a tactic using the new API. For simplicity, a simple ITacticApplication is used, but a IPositionApplication should be used instead. The underlying IReasoner (ExampleReasoner) is not shown here, as it is not impacted by the new API.

//rewrites occurrences of literal 4 into either 2+2 or 2*2 
public class ExampleTacticProvider2 implements ITacticProvider2 {

    // our own implementation of a tactic application
    private static class ExampleApplication implements ITacticApplication {

        private static final String TACTIC_ID = "fr.systerel.example";
    	
        private final Predicate hyp;
        private final IPosition position;
        // 2 Kinds: PLUS (2+2) and MULT (2*2)
        private final ExampleReasoner.Kind kind;

        public ExampleApplication(Predicate hyp, IPosition position, Kind kind) {
            this.hyp = hyp;
            this.position = position;
            this.kind = kind;
        }

        public ITactic getTactic(String[] inputs, String globalInput) {
            // ExampleReasoner implements IReasoner and rewrites literal 4
            // at given position into:
            // . 2+2 if input.kind is PLUS
            // . 2*2 if input.kind is MULT
            return BasicTactics.reasonerTac(
                    new ExampleReasoner(),
                    new ExampleReasoner.Input(hyp, position, kind));
        }

        public String getTacticID() {
            return TACTIC_ID;
        }
    }

    // visits a formula and adds applications on occurrences of literal 4
    private static class ExampleApplicationVisitor extends DefaultVisitor {

        private final Predicate hyp;
        private final Predicate predicate;
        // a list to put applications into
        private final List<ITacticApplication> applications =
                new ArrayList<ITacticApplication>();

        public ExampleApplicationVisitor(Predicate predicate, Predicate hyp) {
            this.predicate = predicate;
            this.hyp = hyp;
        }

        public List<ITacticApplication> getApplications() {
            return applications;
        }

        @Override
        public boolean visitINTLIT(IntegerLiteral lit) {
            if (lit.getValue().intValue() == 4) {
                final IPosition position = predicate.getPosition(lit.getSourceLocation());
                applications.add(new ExampleApplication(hyp, position, Kind.MULT));
                applications.add(new ExampleApplication(hyp, position, Kind.PLUS));
            }
            return true;
        }
    }

    // the ITacticProvider2 interface method: calls the visitor on the predicate
    public List<ITacticApplication> getPossibleApplications(IProofTreeNode node,
                                                            Predicate hyp,
                                                            String globalInput) {

        final Predicate pred = (hyp == null) ? node.getSequent().goal() : hyp;

        ExampleApplicationVisitor visitor =
                new ExampleApplicationVisitor(pred, hyp); 
        pred.accept(visitor);
        return visitor.getApplications();
    }
}