func (r1cs *R1CS) Solve(assignment backend.Assignments, a, b, c, wireValues []fr.Element) error {
	debug.Assert(len(a) == r1cs.NbConstraints)
	debug.Assert(len(b) == r1cs.NbConstraints)
	debug.Assert(len(c) == r1cs.NbConstraints)
	debug.Assert(len(wireValues) == r1cs.NbWires)
	wireInstantiated := make([]bool, r1cs.NbWires)
	instantiateInputs := func(offset int, visibility backend.Visibility, inputNames []string) error {
		for i := 0; i < len(inputNames); i++ {
			name := inputNames[i]
			if name == backend.OneWire {
				wireValues[i+offset].SetOne()
				wireInstantiated[i+offset] = true
			} else {
				if val, ok := assignment[name]; ok {
					if visibility == backend.Secret && val.IsPublic || visibility == backend.Public && !val.IsPublic {
						return fmt.Errorf("%q: %w", name, backend.ErrInputVisiblity)
					}
					wireValues[i+offset].SetBigInt(&val.Value)
					wireInstantiated[i+offset] = true
				} else {
					return fmt.Errorf("%q: %w", name, backend.ErrInputNotSet)
				}
			}
		}
		return nil
	}
	debug.Assert(len(r1cs.PrivateWires) == r1cs.NbPrivateWires)
	debug.Assert(len(r1cs.PublicWires) == r1cs.NbPublicWires)
	if r1cs.NbPrivateWires != 0 {
		offset := r1cs.NbWires - r1cs.NbPublicWires - r1cs.NbPrivateWires  
		if err := instantiateInputs(offset, backend.Secret, r1cs.PrivateWires); err != nil {
			return err
		}
	}
	{
		offset := r1cs.NbWires - r1cs.NbPublicWires  
		if err := instantiateInputs(offset, backend.Public, r1cs.PublicWires); err != nil {
			return err
		}
	}
	var check fr.Element
	for i, r1c := range r1cs.Constraints {
		if i < r1cs.NbCOConstraints {
			r1cs.Constraints[i].solveR1c(wireInstantiated, wireValues)
		}
		a[i], b[i], c[i] = r1c.instantiate(r1cs, wireValues)
		check.Mul(&a[i], &b[i])
		if !check.Equal(&c[i]) {
			invalidA := a[i]
			invalidB := b[i]
			invalidC := c[i]
			return fmt.Errorf("%w: %q * %q != %q", backend.ErrUnsatisfiedConstraint,
				invalidA.String(),
				invalidB.String(),
				invalidC.String())
		}
	}
	return nil
}
Solve sets all the wires and returns the a, b, c vectors.
the r1cs system should have been compiled before. The entries in a, b, c are in Montgomery form.
assignment: map[string]value: contains the input variables
a, b, c vectors: ab-c = hz
wireValues =  [intermediateVariables | privateInputs | publicInputs]
package backend_bn256
import (
	"fmt"
	"strconv"
	"github.com/consensys/gnark/backend"
	"github.com/consensys/gurvy/bn256/fr"
	"github.com/consensys/gnark/frontend"
	"github.com/consensys/gnark/internal/utils/debug"
)
type R1CS struct {
	NbWires        int
	NbPublicWires  int  
	NbPrivateWires int
	PrivateWires   []string          
	PublicWires    []string          
	WireTags       map[int][]string  
	NbConstraints   int  
	NbCOConstraints int  
	Constraints     []R1C
}
func New(cs *frontend.CS) R1CS {
	r1cs := cs.ToR1CS()
	return Cast(r1cs)
}
func Cast(r1cs *frontend.R1CS) R1CS {
	toReturn := R1CS{
		NbWires:         r1cs.NbWires,
		NbPublicWires:   r1cs.NbPublicWires,
		NbPrivateWires:  r1cs.NbPrivateWires,
		PrivateWires:    r1cs.PrivateWires,
		PublicWires:     r1cs.PublicWires,
		WireTags:        r1cs.WireTags,
		NbConstraints:   r1cs.NbConstraints,
		NbCOConstraints: r1cs.NbCOConstraints,
	}
	toReturn.Constraints = make([]R1C, len(r1cs.Constraints))
	for i := 0; i < len(r1cs.Constraints); i++ {
		from := r1cs.Constraints[i]
		to := R1C{
			Solver: from.Solver,
			L:      make(LinearExpression, len(from.L)),
			R:      make(LinearExpression, len(from.R)),
			O:      make(LinearExpression, len(from.O)),
		}
		for j := 0; j < len(from.L); j++ {
			to.L[j].ID = from.L[j].ID
			to.L[j].Coeff.SetBigInt(&from.L[j].Coeff)
		}
		for j := 0; j < len(from.R); j++ {
			to.R[j].ID = from.R[j].ID
			to.R[j].Coeff.SetBigInt(&from.R[j].Coeff)
		}
		for j := 0; j < len(from.O); j++ {
			to.O[j].ID = from.O[j].ID
			to.O[j].Coeff.SetBigInt(&from.O[j].Coeff)
		}
		toReturn.Constraints[i] = to
	}
	return toReturn
}