       column += ']'
       matrix += column
       matrix += ',' unless i == rowCount
-    statement = 'matrix(' + matrix + ')'
-    nerd = nerdamer(statement)
-    result =
-      nerd: nerd
-      tex: nerd.toTeX().replace(/vmatrix/g, 'pmatrix')
-      statement: statement
-    return result
-  else if type == 'MampfTuple'
+    expression = 'matrix(' + matrix + ')'
+    new MampfMatrix(expression)
+
+class MampfTuple
+  constructor: (@expression) ->
+    @nerd = nerdamer(@expression)
+    @length = parseInt(nerdamer('size(' + @expression + ')'))
+    texRaw = @nerd.toTeX()
+    @tex = '(' + texRaw.substr(1, texRaw.length - 2) + ')'
+
+  equals: (otherTuple) ->
+    return false unless @length == otherTuple.length
+    result = true
+    for i in [1..@length]
+      c1 = nerdamer('vecget(' + @expression + ',' + (i-1) + ')')
+      c2 = nerdamer('vecget(' + otherTuple.expression + ',' + (i-1) + ')')
+      result = false unless c1.expand().eq(c2.expand())
+    result
+
+  @parse: (content) ->
     coeffs = content['question[solution_content[0]]']
-    statement = 'vector(' + coeffs + ')'
-    nerd = nerdamer(statement)
-    texRaw = nerd.toTeX()
-    tex = '(' + texRaw.substr(1, texRaw.length - 2) + ')'
-    result =
-      nerd: nerd
-      tex: tex
-      statement: statement
-    return result
-  else if type == 'MampfSet'
+    expression = 'vector(' + coeffs + ')'
+    new MampfTuple(expression)
+
+class MampfSet
+  # note that we assume here that redundant elements have already been removed
+  # from the expression (as it is done in the parse class method)
+  constructor: (@expression) ->
+    @nerd = nerdamer(@expression)
+    @size = parseInt(nerdamer('size(' + @expression + ')'))
+    texRaw = @nerd.toTeX()
+    @tex = '\\{' + texRaw.substr(1, texRaw.length - 2) + '\\}'
+
+  equals: (otherSet) ->
+    return false unless @size == otherSet.size
+    result = true
+    if @size > 0
+      for i in [1..@size]
+        c1 = nerdamer('vecget(' + @expression + ',' + (i-1) + ')')
+        found = false
+        for j in [1..@size]
+          c2 = nerdamer('vecget(' + otherSet.expression + ',' + (j-1) + ')')
+          found = true if c1.expand().eq(c2.expand())
+        result = false unless found
+    result
+
+  @parse: (content) ->
     elements = content['question[solution_content[0]]'].split(',')
     size = elements.length
     nerds = []

  $('#solution-error').empty()
  $('#solution-box').hide()
  try
    expression = extractSolution()
  catch err
    expression = 'Syntax Error'
  if expression == 'Syntax Error'
    $('#solution_input_tex').val('')
    $('#solution_input_error').val(expression)
    $('#solution_content_nerd').val('')
    $('#question_result').val(false)
  else
    latex = expression.tex
    $('#solution_input_tex').val(latex)
    $('#question_quiz_solution_input').val('$' + latex + '$')
    $('#solution_input_error').val('')
    $('#solution_content_nerd').val(expression.statement)
    if $('#question_result').length > 0
      compareToSolution(expression.statement)
  $('#submit-solution').hide()
  return


      unless duplicate
        nerds.push nerd
        set.push element
    expression = 'vector(' + set.join(',') + ')'
    new MampfSet(expression)

class MampfSolution
  constructor: (@type, @details) ->

  equals: (otherSolution) ->
    return false unless @type == otherSolution.type
    @details.equals(otherSolution.details)

  @parse: (content) ->
    type = content['question[solution_type]']
    details = switch
      when type == 'MampfExpression' then MampfExpression.parse(content)
      when type == 'MampfMatrix' then MampfMatrix.parse(content)
      when type == 'MampfTuple' then MampfTuple.parse(content)
      when type == 'MampfSet' then MampfSet.parse(content)
    new MampfSolution(type, details)

  @fromExpression: (type, expression) ->
    details = switch
      when type == 'MampfExpression' then new MampfExpression(expression)
      when type == 'MampfMatrix' then new MampfMatrix(expression)
      when type == 'MampfTuple' then new MampfTuple(expression)
      when type == 'MampfSet' then new MampfSet(expression)
    new MampfSolution(type, details)

extractSolution = ->
  content  = $('#solution-form').serializeArray().reduce(((obj, item) ->
    obj[item.name] = item.value
    obj
  ), {})
  MampfSolution.parse(content)

compareToSolution = (solutionInput) ->
  solutionString = $('#question_nerd').val()
  type = $('#question_solution_type').val()
  solution = MampfSolution.fromExpression(type, solutionString)
  result = solutionInput.equals(solution)
  $('#question_result').val(result)
  if result
    $('#quiz_question_crosses').val($('#quiz_question_crosses').data('answer'))
