Esempio n. 1
0
class Plot(form.Form):
    """Plot functions"""

    functions = fields.ExpressionList("Functions", required=True)
    x = fields.Expression("Variable", default="x")
    x_min = fields.Expression("x min", default="-10")
    x_max = fields.Expression("x max", default="10")
    equal_aspect = fields.Boolean("Equal aspect", default=True)

    template = """
        <div v-if="config.edit">
            Plot `functions` for `x` between `x_min` and `x_max`
        </div>
        `plot`
    """

    @fields.computed("Plot", field=fields.Html, nohide=True)
    @fields.figure
    def plot(self):
        """Use SymPy/matplotlib to generate an SVG graph"""
        data = (self.x, self.x_min, self.x_max)
        graph = sympy.plot(*self.functions, data, show=False, ylabel="y")
        colors = [False, 'red', 'green', 'orange']
        for index in range(len(self.functions)):
            if index < len(colors) and colors[index]:
                graph[index].line_color = colors[index]
        backend = graph.backend(graph)
        backend.matplotlib.use("agg")
        backend.process_series()
        backend.fig.tight_layout()
        ax = backend.ax[0]
        if self.equal_aspect:
            ax.axis("tight")
            ax.set_aspect("equal")
        ax.grid(True)
Esempio n. 2
0
class EulerMethod(form.Form):
    """Euler method"""

    template = """
        <ul>
            <li><span class="katex">f(x, y) =</span> `function`</li>
            <li>Initial condition: `x0`, `y0`</li>
            <li><span class="katex">h = </span> `h`</li>
            <li><span class="katex">n = </span> `n`</li>
            <li v-if="config.edit">`midpoint`</li>
        </ul>
        `solution`
    """

    function = fields.Expression("Function", required=True)
    x0 = fields.Expression("Initial condition (x)", required=True)
    y0 = fields.Expression("Initial condition (y)", required=True)
    h = fields.Expression("Step length", default="0.1")
    n = fields.Expression("Number of iterations", default="3")
    midpoint = fields.Boolean("Use midpoint method")

    @fields.computed("Solution")
    def solution(self):
        x, y, old_y = self.x0, self.y0, self.y0
        for k in range(self.n):
            grad = self.function.subs({"x": x, "y": y})
            if self.midpoint and k > 0:
                new_y = old_y + grad * 2 * self.h
                old_y, y = y, new_y
            else:
                y += grad * self.h
            x += self.h
        return (x.evalf(), y.evalf())
Esempio n. 3
0
class Taylor(form.Form):
    """Taylor Expansion"""

    template = """
        Taylor expansion of `expression`
        of order `order`
        <span v-if="config.edit || payload.x != 'x'">
            with respect to `x`
        </span>
        around `x0`.
        <p v-if="config.edit">
            `show_graph`
            Distance to `x0`: `h`
        </p>
        `taylor`
        <div v-if="payload.show_graph">`graph`</div>
    """

    expression = fields.Expression("Expression")
    x = fields.Expression("x", default="x")
    order = fields.Expression("Order", default=6)
    x0 = fields.Expression("x0", default=0)
    show_graph = fields.Boolean("Show graph", default=False)
    h = fields.Expression("h", default="1")

    @fields.computed("Taylor expansion")
    def taylor(self):
        return sympy.series(self.expression,
                            x=self.x,
                            x0=self.x0,
                            n=self.order + 1)

    @fields.computed("Plot", field=fields.Html, nohide=True)
    def graph(self):
        return plot.Plot(
            functions=[self.expression, self.taylor.removeO()],
            x=self.x,
            x_min=self.x0 - self.h,
            x_max=self.x0 + self.h,
        ).plot
Esempio n. 4
0
class Equation(form.Form):
    """Equation"""

    name = fields.Field("Survey name")
    answer = fields.ExpressionList("Your answer", nosave=True, editable=True)
    equation = fields.Equation("Equation", required=True)
    x = fields.Expression("Solve for", default="x", required=True)
    template = """
        Solve `equation` <span v-if="config.edit || payload.x !== 'x'">for `x`</span>
        <div v-if="!payload.marked_question">`solution`</div>
        <div v-else>
            <survey
                :config="config"
                :name="payload.name"
                :showStats="config.authState.loggedIn"
                :correct="computed.correct"
                :value="payload.answer">
                Solution(s): `x` = `answer`
            </survey>
        </div>
        <div v-if="config.edit">
            `show_graph`
            `marked_question`
        </div>
        <div v-if="payload.show_graph">`graph`</div>
    """
    show_graph = fields.Boolean("Show graph", default=False)
    marked_question = fields.Boolean("Marked question", default=False)
    h = fields.Expression("h", default="3")

    @fields.computed("Correct", field=fields.Boolean)
    def correct(self):
        if not self.answer:
            return False
        # Prevent user from just copying the equation
        for sol in self.answer:
            if len(sol.atoms(sympy.Symbol)):
                return False
        solution = sympy.solveset(self.equation, self.x)
        sol_count = len(solution.args)
        return len(solution.intersect(
            sympy.FiniteSet(*self.answer)).args) >= sol_count

    @fields.computed("Solution")
    def solution(self):
        answer = sympy.solveset(self.equation, self.x)
        if answer.func == sympy.FiniteSet and len(answer.args) <= 3:
            answer = [
                sympy.Eq(self.x, answer.args[i])
                for i in range(len(answer.args))
            ]
        return answer

    @fields.computed("Plot", field=fields.Html, nohide=True)
    def graph(self):
        if not self.show_graph:
            return ""
        args = {"functions": [self.equation.args[0], self.equation.args[1]]}
        if isinstance(self.solution, list) and len(self.solution) in [1, 2]:
            if len(self.solution) == 1:
                solution = self.solution[0].args[1]
            if len(self.solution) == 2:
                x1, x2 = self.solution[0].args[1], self.solution[1].args[1]
                solution = (x1 + x2) / 2
                self.h = x2 - solution + 2
            args.update({
                "x_min": solution - self.h,
                "x_max": solution + self.h
            })
        return plot.Plot(**args).plot

    def validate(self):
        if self.marked_question:
            if self.show_graph:
                self.show_graph = False
            if not self.name:
                self.name = str(uuid.uuid1())