Hello everyone,
can some one point me in the direction to implement Graph UI questions. a simple example will do.
thanks
Hello everyone,
can some one point me in the direction to implement Graph UI questions. a simple example will do.
thanks
There's a demo quiz of the GraphUI here: https://coderunner.org.nz/mod/quiz/view.php?id=466. It consists of a description of how the GraphUI works followed by a single demo question. Check it out and see if it's sufficient to get you going. The description preceding the question now includes a link to allow you to download a Moodle XML export of the question. If you import the question, you can study the template to see how it works. I've added lots of comments to help explain it.
You can also inspect the DirectedGraph and UndirectedGraph question types (e.g. by creating a question of such a type and checking Customise to allow you to see the template). The only difference between directed and undirected graphs is in the setting of a template parameter isdirected. If you want a Finite State Machine graph, which allows incoming edges from empty space and marking of accept nodes by double clicking, set a template parameter isfsm to true. Other template parameters allow setting of font size and node radius, and provide a rather clumsy way of locking edges or nodes, useful if you wish to provide a sample answer to students and you don't want them to change some aspects of it. These are documented here.
Post back here if you need more info.
An example would be: given a non-deterministic finite automaton, construct a deterministic one that accepts the same language. The expected automaton is drawn as a labelled graph, just as it would be on paper. You can get ideas for automata/grammar questions from tools such as Exorciser https://www.swisseduc.ch/compscience/exorciser/index.html and JFLAP http://www.jflap.org/
The question author provides the correct answer (also by drawing a graph). A student's answer is compared against that. As you suggest, you can test all strings up to a certain length and/or some longer, random strings. If you find a string that is not correctly handled, it can be given to the student as feedback. For finite automata, there are decision procedures which can determine the correctness without testing any strings, but in practice testing is enough as there are usually short counterexamples and having these is useful for students to correct their answers. Also the testing method extends to more general automata such as pushdown automata or Turing machines whose equivalence is undecidable.
This method has been applied to other formalisms such as grammars or regular expressions (these don't need a graphical input). For grammars, you can generate all strings up to a certain length in the language generated by the student's grammar and compare them with the language generated by the correct grammar. The method can be applied to any formalism for which you can create a parser for the students' answers and an automated testing/verification procedure.
import json
from automata.fa.dfa import DFA
import automata
student_answer = """{{ STUDENT_ANSWER | e('py') }}"""
SEPARATOR = "##"
error_count = 0
def error(s):
global error_count
print(s)
error_count += 1
class ValidationError(Exception):
pass
try:
graph_rep = json.loads(student_answer)
node_id_to_name_map = {}
for i, node in enumerate(graph_rep['nodes']):
node_id_to_name_map[i] = node[0] if node[0] != '' else ('#' + str(i))
edges = graph_rep['edges']
nodes = [ node[0] for node in graph_rep['nodes'] if node[0] != "" ]
end_nodes = [ node[0] for node in graph_rep['nodes'] if node[0] != "" and node[1] == True]
labels = [ edge[2] for edge in graph_rep['edges'] if edge[2] != ""]
graph = {}
start_nodes = set()
for node_id, node_name in sorted(node_id_to_name_map.items()):
edges = dict()
for source, target, edge_label in graph_rep['edges']:
if source == node_id:
edges[edge_label] = node_id_to_name_map[target]
if source == -1:
start_nodes.add(node_id_to_name_map[target])
graph[node_name] = edges
if len(start_nodes) > 1:
raise ValidationError("Too many initial states")
dfa = DFA(
states= set(nodes),
input_symbols=set(labels),
transitions=graph,
initial_state=start_nodes.pop(),
final_states=set(end_nodes)
)
except json.JSONDecodeError as e:
raise Exception("Oops. Illegal graph received (exception {}). Please report (unless you did something silly yourself)".format(e))
except automata.base.exceptions.MissingStateError as e:
print("Validation Error:" + str(e))
except ValidationError as e:
print("Validation Error:" + str(e))
{% for TEST in TESTCASES %}
if dfa.accepts_input("{{ TEST.stdin }}"):
print(True)
else:
print(False)
{{ TEST.extra }}
{% if not loop.last %}
print(SEPARATOR)
{% endif %}
{% endfor %}
@17943918#@>